🔐

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はガロア体演算に由来してるらしい(ナニソレ)
    • 認証タグを生成して、改ざん検出を行う
  • 流れ
    1. 初期化ベクトル(IV) + カウンターで各ブロックを暗号化
    2. 暗号化された各ブロックを合成
    3. さらに、ヘッダーとデータも含めてMAC(認証タグ)を生成
  • 利点
    • 処理が早くて安全性も高い(TLS1.2以降では標準装備)

JWEの処理の流れ

暗号化編(送信者)
  1. ペイロードの準備
  2. コンテンツ暗号鍵(CEK)をランダム生成
  3. CEKを KMA (Key Management Algorithm)に従って暗号化
  4. ペイロードをCEKで CEA (Content Encryption Algorithm)に従って暗号化
  5. Protected Header, Encrypted Key, Initialization Vector, Ciphertext, Authentication TagをBase64URLエンコードして結合
  6. .で区切ってJWEを生成
復号編(受信者)
  1. JWE文字列を分解して各パートを取得
  2. Protected Headerをデコードして、使用アルゴリズムなどを確認
  3. Encrypted Keyを受信者の秘密鍵で復号してCEKを取得
  4. CEK と Initialization Vectorを使用して、Ciphertextを復号
  5. ペイロードを取得
  6. 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の作成と検証について。

作成ステップ

  1. クレームセットの作成
  2. クレームセットのUTF-8エンコード
  3. JOESヘッダーの作成
  4. JWS、JWEの作成
  5. 必要であればネストや署名

検証ステップ

  1. JWTの構造確認
  2. JOSEヘッダーのデコードと解析
  3. ヘッダーの検証
  4. JWTタイプの判定
    • 署名?暗号化?
  5. 署名、暗号化の検証
  6. クレームの検証

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

あくまでJWTだよっていう宣言に過ぎないので、実際にしっかり検証する必要がある。

10. IANA Considerations

IANA(Internet Assigned Numbers Authority)に対して登録されている識別子について。

  1. JWT Claim Names Registry
    • 標準的なクレームのリスト
      • iss,sub,audなど
  2. Media Type application/jwt
  3. Token Type URI

11. Security Considerations

セキュリティに関するガイドライン。

  1. 信頼の決定
    • 暗号的な保護
    • 発行者の検証→署名
  2. Nested JWTs
    • 署名と暗号化の順序
    • 検証の複雑性→各レイヤーで適切な順番等で検証する必要がある
  3. JSONおよびUnicodeのセキュリティ考慮事項
    • JSON解析時に予期しない構造やデータ型がセキュリティ上の問題を引き起こす可能性がある
    • Unicodeの比較時には注意

12. Privacy Considerations

ユーザー識別子とかメアドなどの個人情報に準じる情報が詰まることがあるので、注意が必要。

  • アンチパターン

    • URLに含める
    • ログに出す
    • ブラウザのローカルストレージに保存する
    • 必要最小限の情報の原則に従ったクレーム
  • 対応

    • 署名、暗号化のどちらも
    • 有効期限は短く!

JWTのうれしみと比較

トークンベース認証

認証成功時にサーバーが署名付きJWTトークンを発行しクライアントに返却する。
クライアントは各リクエストでJWTトークンを添付し、サーバーはクライアントより受け取るトークンを検証することで認可できる。

  • メリット😳
    • ステートレス
    • スケーラビリティがある
    • 自己完結
    • サードパーティ、SSOにつよい
    • リバースプロキシ、CDNでも検証可能
  • デメリット😈
    • 失効制御が複雑になる
    • トークンの漏洩が重大なセキュリティリスクになる
    • ペイロードを改ざんできなくても中身は閲覧できる

参考: セッションベース認証

Cookie+サーバーセッション。
認証成功時にサーバーがセッションIDを発行、各リクエストでサーバー側でID→ユーザー情報をDBやメモリ上のセッションストアから引き出す。

  • メリット😳
    • サーバーで状態管理しているので、失効制御が柔軟
    • 強制ログアウトなどが即時反映できる
    • 一時的、頻繁な状態保存に適する
  • デメリット😈
    • スケーリングが大変
    • ステートフル
    • セッション漏洩が重大なセキュリティリスクになる

話を広げるなら?
OAuth/OIDCかなぁ、これは別で勉強しよう。


まとめ

己の怠惰に負け、強烈なモチベーションがないと普段使っている技術の根底について深堀りしようなんて気持ちにならないんですよね。
だが、泣くほど恥ずかしい思いをしたので、ふて寝で済まさずただでは起きない気持ちでいきたいです。

(終盤は燃え尽きた感が否めないので追記の可能性は大)

それはそうとして図的に技術を理解、表現するのって数こなさないとできなそうですよね。

ref/蛇足

ほぼ愛のある手書き。
ところどころChatGPTに壁打ちしたが、内容は私の理解。

Discussion