utsuroi jwt labs知識ベース 01 / 01
JSON Web Token · Knowledge Base
01

JWT の基礎

A self-contained token, with self-inflicted wounds

JWT(JSON Web Token)は「自己完結型のトークン」として広く使われていますが、仕様の柔軟性が攻撃面の広さに直結している。alg ヘッダの扱い、鍵の取り違え、署名検証の手抜きなど、各実装のミスが現役の攻撃ベクトルです。

1. JWT の構造 #structure

JWT は3つの base64url エンコード部分をドット . で連結した文字列。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJyb2xlIjoidXNlciJ9.{signature}
        ^                                ^                                  ^
   ヘッダ(JSON)                       ペイロード(JSON)                 署名

ヘッダとペイロードは暗号化されておらず、誰でも base64 デコードして読める(機密情報を入れてはいけない)。

2. alg=none 攻撃 #alg-none

JWT 仕様には alg: "none"(署名なし)モードが定義されています。これを「デバッグ用」「テスト用」と思って実装に残したサーバが攻撃される。

// 攻撃者が改ざん:
ヘッダ:  {"alg":"none","typ":"JWT"}
ペイロード: {"sub":"123","role":"admin"}
署名:    (空文字列)

サーバが alg ヘッダの値をそのまま信頼して「none なら署名検証スキップ」と実装していると、攻撃者は何でも書き換えられる。

3. alg confusion(HS256 / RS256 取り違え) #alg-confusion

典型的な事例。サーバが RS256(公開鍵暗号、署名は秘密鍵で、検証は公開鍵で)で運用しているとする。攻撃者は alg を HS256(共通鍵暗号、HMAC)に書き換え、公開鍵をそのまま HMAC の鍵として使って署名する。

  1. サーバの公開鍵を入手(/.well-known/jwks.json 等で公開されている)
  2. JWT の alg を RS256 → HS256 に書き換え、ペイロードを改ざん
  3. 公開鍵を HMAC 鍵として、改ざんしたヘッダ+ペイロードに対する HS256 署名を計算
  4. サーバ側のコードが jwt.verify(token, public_key) と書かれていて、alg を JWT 内の値に従ってしまうと、HS256 として公開鍵を HMAC 鍵に使って検証 → 一致 → トークンが正当と判定される

これは仕様の柔軟性とライブラリのデフォルトが噛み合った結果。「期待する alg をサーバ側で明示的に指定」することで防げる。

4. 弱い HMAC 鍵のブルートフォース #weak-secret

HS256 系で短い・予測可能な鍵(secretpassword、社名等)を使っていると、JWT 自体は公開情報なので hashcat 等でオフライン総当たり可能。

$ hashcat -a 0 -m 16500 jwt.txt /usr/share/wordlists/rockyou.txt

HMAC 鍵には 256bit 以上の暗号論的にランダムな値を使う。Argon2/bcrypt とは別物で、こちらは「速く検証する必要があるので低速ハッシュは使えない」が、鍵のエントロピーは確保する必要がある。

5. 正しい防御 #defense

  1. 検証時に期待する alg を明示jwt.verify(token, key, { algorithms: ['RS256'] }) と書く。JWT 内の alg ヘッダは信用しない
  2. none アルゴリズムは禁止 — ライブラリ・設定で alg=none を絶対に許可しない
  3. 鍵の管理 — HMAC 鍵は CSPRNG で生成した 256bit 以上。秘密鍵は HSM や KMS に
  4. ペイロードに機密情報を入れない — base64 デコードで誰でも読める。ID 程度に留める
  5. 有効期限を短くexp を短く(15分等)。漏洩時の被害時間を限定。リフレッシュトークンと併用
  6. サーバ側で失効リストを持つ — JWT は本来「ステートレス」だが、ログアウト・侵害発覚時の即時無効化のため、失効リスト(またはセッション ID 連動)が現実的
  7. セッション Cookie で十分なら使う — マイクロサービス間の認証等で必要なケース以外、伝統的なサーバセッションの方が安全な選択肢