JWTについて詳しくなる
JWT (JSON Web Token)について詳しくなる
とあるきっかけで雰囲気でしかJWTを使っていないことを多大なる羞恥と悔悟とともに痛感したので、禊としてここに自分の最大限の努力を持ってJWTについてまとめます。
技術深堀りシリーズになるのではと思っています。
心魂が折れない限りは続けます。
JWTとは
JWTは、JSON Web Tokenの略。
RFC 7519で定義されている、JSON形式のトークンを使用して情報を安全に転送するためのオープンな標準。
JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.
もう何言っているか分からんですね。
RFC 7519
JWTの標準仕様をまとめている。
章番号 | タイトル | 内容の要約 |
---|---|---|
1 | Introduction | JWTの概要を説明。JWTがどんな課題を解決するか、なぜ必要かを示している。 |
2 | Terminology | JWT仕様書で使われる主要な用語(クレーム、エンティティ、JOSEヘッダーなど)の定義。 |
3 | JSON Web Token (JWT) Overview | JWTの基本構造(Header, Payload, Signature)やコンパクトシリアライゼーションについて解説。 |
4 | JWT Claims | JWTに含まれる情報(クレーム)の種類、目的、標準/公開/非公開クレームの区別を詳細に説明。 |
5 | JOSE Header | JOSEヘッダーの役割と、その中で指定できるパラメータや暗号化/署名方式の記述方法を解説。 |
6 | Unsecured JWTs | 署名・暗号化されていないJWT(alg=none)の仕様と、そのリスクについて解説。 |
7 | Creating and Validating JWTs | JWTの生成と検証の標準的な手順を具体的に説明。署名・暗号化のフローや注意点も含む。 |
8 | Implementation Requirements | JWT実装で最低限サポートすべきアルゴリズムや機能を明示。推奨アルゴリズムも挙げている。 |
9 | URI for Declaring that Content is a JWT | JWTを表すURN("urn:ietf:params:oauth:token-type:jwt")の登録とその用途について説明。 |
10 | IANA Considerations | JWTの標準クレーム名などのレジストリ管理、IANAへの登録手順について記載。 |
11 | Security Considerations | JWT利用時のセキュリティリスク(リプレイ攻撃、クレーム改ざん、鍵管理など)とその対策をまとめている。 |
12 | Privacy Considerations | JWTによる個人情報漏洩のリスクやプライバシーへの影響、設計時の留意点を記載。 |
13 | References | 仕様に関連する他のRFCや文献の一覧。 |
ref: RFC 7519
RFCが体系的にまとまっているので、これに従った章立てでいきます卍。
2. Terminology (用語)
Claimとか、基本的な要素を定義している。
ここで前提になりそうな用語を勝手に深堀り
対称鍵と公開鍵って結局何が違うの?
対称鍵暗号
同じ鍵で暗号化と復号を行う。
ex: AES、ChaCha20
早いが鍵の共有がネックになる。
公開鍵暗号
公開鍵と秘密鍵を使う。
ex: RSA、 ECSSA, ECDH
処理自体は思いが安全。
AESってなんぞ
AES(Advanced Encryption Standard)対称鍵暗号方式。
FIPS 197で採用されているらしい。
- 特徴
- ブロック暗号
- データを128ビットで区切って処理する
- 鍵長
- 128/192/256bitの3種
- はやい
- ブロック暗号
ざっくり
→ データを16バイトで区切って、鍵を使ってシャッフル
さらに
処理名 | 概要 |
---|---|
SubBytes | 各バイトに置き換える (S-Box) |
ShiftRows | 行をずらして混ぜる |
MixColumns | 列ごとに計算して更にシャッフル |
AddRoundKey | 鍵とXOR |
この処理の回数でAES-128などが決まるMax 14回。
-
つよみ
- 数学的に差分・線形攻撃に強い
- ブルートフォース攻撃が難しい
-
ユースケース
- HTTPS(TLS)
- VPN
- WPA2/WPA3
- AWSのKMS
- JWEの Payload
- ファイルの暗号化(zip, pdf, disk)
モードと組み合わせる。
モードってなんぞ?
ブロック暗号(AESなど)をどう使うか?のルールセットを指す。
どゆこと?
→ AWSは固定長のブロック単位でしか暗号化できない。
→→ 複数ブロックをどう繋げて暗号化するか を決めるのがモード。
モード | 特徴 | 安全性 | 認証 | 用途 |
---|---|---|---|---|
ECB | 各ブロックで独立して暗号化 | 同じ入力と同じ出力でパターンがバレる | ☒ | 古い、非推奨 |
CBC | 一つ前の暗号文と次の平文をXORして暗号化 | ◯(初期化ベクトル必要) | ☒ | ファイル暗号など |
CFB / CTR | ストリーム的に使える | ◯ | ☒ | 暗号化通信など |
GCM | CTR+認証タグで改ざん検知 | ◎ | ☑ | JWE,TLSなど |
CCM | 暗号+認証だがGCMより処理が重い | ◯ | ☑ | 軍事 IoT |
- CBC
- 各ブロックを前の暗号ブロックとXOR
- 初期化ベクトルが必須
- 改ざん検知ができない
- パディングオラクル攻撃?に弱い
- GCM
- Galois領域演算で改ざん検知の認証タグを生成できる
- 並行処理が可能
- CTRモードだから各暗号ブロックでカウンター値が異なるのでそれぞれ処理できる
Galois演算領域って?
何も分からんが
→ 有限体GF(2^128)という数学の計算空間らしい。
- XOR → 加算
- ビット操作 → 乗算
もう少し頭が良くなったら戻ってこよう(要追記)
3. JSON Web Token (JWT) Overview
Header.Payload.Signature
の3部構成。
各部はBase64URLエンコードされ、ドットで区切られる。
JWS形式について
デジタル署名またはMAC(Massage Authentication Code)を使用して、JWTの内容を保護する形式。
発信者の正当性を保証することが一番の目的。
JWSの構造
形式 | 用途と特徴 |
---|---|
JWS Compact Serialization | 軽量。JWTでよく使われれる。URLセーフで1行で表現冴えれる。 |
JWS JSON Serialization | 複数署名や署名の詳細が必要なときに使われる。JSON形式で表現され、複雑なユースケースに対応。 |
JWS Compact Serializationの例
<base64url(JWSヘッダー)>.<base64url(ペイロード)>.<base64url(署名)>
よく見るやつね。
JWS JSON Serializationの例
{
"payload": "<base64url(ペイロード)>",
"signatures": [
{
"protected": "<base64url(JWSヘッダー)>",
"header": { "kid": "12345" },
"signature": "<base64url(署名)>"
},
...
]
}
protectedは署名対象。headerは署名に関するメタデータ。
めずらしい? あんまみない。
署名アルゴリズムは力尽きなければ本記事で、力尽きたら別の記事でまとめる。
つまるところ、JWTとの違いは...
JWSはJWTの一部であり、JWTの内容を保護するため形式である。
といえるかな?
JWE形式について
JWE(JSON Web Encryption)は、JWTの内容を暗号化するための形式。
JWS(署名)とは異なり、5つのパートで構成される。
BASE64URL(Protected Header).
BASE64URL(Encrypted Key).
BASE64URL(Initialization Vector).
BASE64URL(Ciphertext).
BASE64URL(Authentication Tag)
パート | 名前 | 説明 |
---|---|---|
Protected Header | ヘッダー | 暗号化方式などのメタ‐データをJSON形式で保存、JOESヘッダーと同様。 |
Encrypted Key | 暗号化キー | コンテンツ暗号鍵(CEK)を受信者の公開鍵などで暗号化したもの。 |
Initialization Vector | 初期化ベクトル | 暗号化アルゴリズムで使用される初期化ベクトル。 |
Ciphertext | 暗号文 | 暗号化されたペイロードデータ。 Claimsなどの情報が含まれる。 |
Authentication Tag | 認証タグ | GCMなどのアルゴリズムで生成された整合性検証用の認証タグ。 |
はい。もう自分でも何書いているかさっぱりわけわかめ。
CEKとは?
CEKとは「実際のデータを暗号化する鍵」のこと。つまり、JWEにおいてコンテンツ本体(Payload)を暗号化するための対称鍵。
- 特徴
- ランダムに生成される一時的な鍵
- 通常はAES(対称鍵暗号)で使われる(例:A128GCM → 128bitのCEK)
- 目的
- JWEのペイロードを暗号化するために使用される。
- JWEでは公開鍵でペイロードを直接暗号化すると処理が重すぎる
初期化ベクトルとは?
暗号化を開始する時に使われる「ランダムな初期値」のこと。
- 特徴
- 暗号化アルゴリズムごとに必要なサイズが決まっている(例:AES-GCMでは12バイト)。
- 同じデータを同じ鍵で暗号化しても、初期化ベクトルが異なれば結果も異なる。
- 目的
- 同じ鍵、同じデータでも初期化ベクトルが異なれば、暗号化結果が異なるため、セキュリティを向上させる。
- 暗号の一意性とセキュリティを確保するために使用される。
公開しても問題ないが、予測不能なランダム性を期待する。
GCMとは?
暗号+認証を同時に行えるAESのモードの1つ
正式には「AES-GCM(Galois/Counter Mode)」と呼ばれる。
- 特徴
- 機密性と完全性・認証(MAC)を同時に提供する
- GCMのGaloisはガロア体演算に由来してるらしい(ナニソレ)
- 認証タグを生成して、改ざん検出を行う
- 流れ
- 初期化ベクトル(IV) + カウンターで各ブロックを暗号化
- 暗号化された各ブロックを合成
- さらに、ヘッダーとデータも含めてMAC(認証タグ)を生成
- 利点
- 処理が早くて安全性も高い(TLS1.2以降では標準装備)
JWEの処理の流れ
暗号化編(送信者)
- ペイロードの準備
- コンテンツ暗号鍵(CEK)をランダム生成
- CEKを KMA (Key Management Algorithm)に従って暗号化
- ペイロードをCEKで CEA (Content Encryption Algorithm)に従って暗号化
- Protected Header, Encrypted Key, Initialization Vector, Ciphertext, Authentication TagをBase64URLエンコードして結合
-
.
で区切ってJWEを生成
復号編(受信者)
- JWE文字列を分解して各パートを取得
- Protected Headerをデコードして、使用アルゴリズムなどを確認
- Encrypted Keyを受信者の秘密鍵で復号してCEKを取得
- CEK と Initialization Vectorを使用して、Ciphertextを復号
- ペイロードを取得
- Authentication Tagを使用して、整合性を検証
なんなの?調べれば調べるほど一向に分からん。
KMAとは?
JWEにおける「Content Encryption Key(CEK)を安全にやり取りする方法(暗号化手法)」。
CEKをどう渡すかを定めた鍵暗号アルゴリズム。
名称 | 概要 | 特徴 |
---|---|---|
RSA-OAEP | 受信者のRSA公開鍵でCEKを暗号化 | 一般に推奨される。安全なパディング=OAEPを使用する。 |
ECDH-ES | 楕円曲線で鍵交換してCEKを共有 | 楕円曲線暗号ではない? わからん (要追記) |
A128KW | AES自体でCEK自体を鍵ラップ | 対象鍵が前提になる。はやい。 |
CEK自体を暗号化するので、安全性が高くなる。
→ 受信者が秘密鍵を持っていないと複合できないので、受信者を限定できる。
CEAとは?
JWEでの「ペイロード本体を暗号化するアルゴリズム」のこと。
名称 | モード | 概要 |
---|---|---|
A128GCM | GCM | 最も推奨される安全なアルゴリズム |
A256GCM | GCM | より強固な鍵長(256bit) |
A128CBC-HS256 | CBC + HMAC | 複雑だが、強固。あんまり使用頻度は高くない? |
JWEは、JWSと違って、受信者が暗号化された内容を復号するための鍵を持っている必要がある。
JWT + JWSの2重構造(Nested JWT)もできる。
→ JWEは発行元の真正性までは担保しない。
ユースケースは?
- 機密データ(個人情報・クレカ情報など)を安全に転送したい場合
- OAuth2/OpenID ConnectでのIDトークンの暗号化
4. JWT Claims
JWT Claims Set
と呼ばれるJSONオブジェクトで構成される。
それぞれの要素がKeyValueで1つのクレーム。
- 標準クレームについても説明されている。
-
iss
: 発行者 (Issuer) -
sub
: 主題 (Subject) -
aud
: 対象者 (Audience) -
exp
: 有効期限 (Expiration Time) -
nbf
: 使用開始時間 (Not Before) -
iat
: 発行時間 (Issued At) -
jti
: JWT ID
-
疲れてきたのでさっぱりいく。
5. JOES Header
JSON Object Signing and Encryption Headers
。
トークン3部構成のうちヘッダーに該当し、JWT・JWEなどのJOSEファミリーで使われるメタデータの部分のこと。
-
Header.Payload.Signature
のうち、Header
の部分。 - フィールド
-
alg
: 使用する署名アルゴリズム。(例: HS256, RS256,PS256など) -
typ
: トークンのタイプ(通常はJWT)。あんまり使わないが異なる種類のオブジェクトが入り交じるときに使う。 -
kid
: キーID(オプション)。どの鍵で署名されたかを示すための識別子。 -
cty
: コンテンツタイプ(オプション)。トークンの内容のメディアタイプを示す。 JWEの中にJWTをネストしている場合などに使われる。
-
{
"alg": "HS256",
"typ": "jwt",
"kid": "12345",
"cty": "application/json"
}
6. Unsecured JWTs
JWTのセキュリティについて。
- 署名や暗号化してね
-
alg
がnoneだとセキュリティリスクになるよ - 有効期限はきちんと確認しようね
- URLに入れると危険なのでなるべくHTTPヘッダーに入れようね
- 自己完結型のため1度発行されると取り消し不可。短めの有効期限にしようね
7. Creating and Validating JWTs
JWTの作成と検証について。
作成ステップ
- クレームセットの作成
- クレームセットの
UTF-8
エンコード - JOESヘッダーの作成
- JWS、JWEの作成
- 必要であればネストや署名
検証ステップ
- JWTの構造確認
- JOSEヘッダーのデコードと解析
- ヘッダーの検証
- JWTタイプの判定
- 署名?暗号化?
- 署名、暗号化の検証
- クレームの検証
8. Implementation Requirements
JWTを使う上での、最低限守るべき必須事項と推奨事項。
前提、JWTの仕様は最低限を規定している。
アプリケーション側で任意にアルゴリズムを足すのはOK
署名・MACアルゴリズム
- MUST
- HS256
- none → 互換性のために。
- RECOMMEND
- RS256
- ES256
- OPTIONAL
- RS256など。
JWEサポート
サポートは必須ではない。
サポートするなら
- MUST
- RSA1_5
- A128KW/A256KW
- A128CBC-HS256
- RECOMMEND
- ECDH-ES+A128KW / A256KW
- A128GCM / A256GCM
Nested JWT
サポート自体が任意。
9. URI for Declaring that Content is a JWT
JWTであることをURIで明示する方法
MIMEタイプで明示する(application/jwt
)が一般だが、URIでも指定可能。
URN(Uniform Resource Name
): URIの一種で「名前空間+名前」で唯一性を担保する識別子。
IETFが登録したURN
urn:ietf:params:oauth:token-type:jwt
- 意味
- urn
- 名前空間を表現するPrefix
- ietf
- IETF=標準化団体の管理下
- params
- 各種標準化プロトコルの定義用
- oauth
- OAuth関連
- token-type
- トークンの種類を表現する
- jwt
- urn
あくまでJWTだよっていう宣言に過ぎないので、実際にしっかり検証する必要がある。
10. IANA Considerations
IANA(Internet Assigned Numbers Authority)に対して登録されている識別子について。
- JWT Claim Names Registry
- 標準的なクレームのリスト
-
iss
,sub
,aud
など
-
- 標準的なクレームのリスト
- Media Type
application/jwt
- Token Type URI
11. Security Considerations
セキュリティに関するガイドライン。
- 信頼の決定
- 暗号的な保護
- 発行者の検証→署名
- Nested JWTs
- 署名と暗号化の順序
- 検証の複雑性→各レイヤーで適切な順番等で検証する必要がある
- JSONおよびUnicodeのセキュリティ考慮事項
- JSON解析時に予期しない構造やデータ型がセキュリティ上の問題を引き起こす可能性がある
- Unicodeの比較時には注意
12. Privacy Considerations
ユーザー識別子とかメアドなどの個人情報に準じる情報が詰まることがあるので、注意が必要。
-
アンチパターン
- URLに含める
- ログに出す
- ブラウザのローカルストレージに保存する
- 必要最小限の情報の原則に従ったクレーム
-
対応
- 署名、暗号化のどちらも
- 有効期限は短く!
JWTのうれしみと比較
トークンベース認証
認証成功時にサーバーが署名付きJWTトークンを発行しクライアントに返却する。
クライアントは各リクエストでJWTトークンを添付し、サーバーはクライアントより受け取るトークンを検証することで認可できる。
- メリット😳
- ステートレス
- スケーラビリティがある
- 自己完結
- サードパーティ、SSOにつよい
- リバースプロキシ、CDNでも検証可能
- デメリット😈
- 失効制御が複雑になる
- トークンの漏洩が重大なセキュリティリスクになる
- ペイロードを改ざんできなくても中身は閲覧できる
参考: セッションベース認証
Cookie+サーバーセッション。
認証成功時にサーバーがセッションIDを発行、各リクエストでサーバー側でID→ユーザー情報をDBやメモリ上のセッションストアから引き出す。
- メリット😳
- サーバーで状態管理しているので、失効制御が柔軟
- 強制ログアウトなどが即時反映できる
- 一時的、頻繁な状態保存に適する
- デメリット😈
- スケーリングが大変
- ステートフル
- セッション漏洩が重大なセキュリティリスクになる
話を広げるなら?
OAuth/OIDCかなぁ、これは別で勉強しよう。
まとめ
己の怠惰に負け、強烈なモチベーションがないと普段使っている技術の根底について深堀りしようなんて気持ちにならないんですよね。
だが、泣くほど恥ずかしい思いをしたので、ふて寝で済まさずただでは起きない気持ちでいきたいです。
(終盤は燃え尽きた感が否めないので追記の可能性は大)
それはそうとして図的に技術を理解、表現するのって数こなさないとできなそうですよね。
ref/蛇足
ほぼ愛のある手書き。
ところどころChatGPTに壁打ちしたが、内容は私の理解。
Discussion