【実務・中級編】 JWTのalg: none脆弱性と鍵の混同攻撃(Key Confusion Attack) – 暗号理論・認証基盤 & エンドポイントセキュリティ防御ガイド

現場のエンジニア諸君、お疲れ様。今日もどこかで認証トークンが不正に書き換えられ、誰かが管理者権限を奪取されているかもしれない。

JWT(JSON Web Token)は現代のWeb開発において「認証の銀の弾丸」のように扱われているが、その仕様の柔軟さが仇となり、多くのシステムが「実装の穴」を突かれて崩壊している。今日は、教科書には載っていない、現場で遭遇する「JWTの悪夢」――alg: none脆弱性と「鍵の混同攻撃(Key Confusion Attack)」について、実戦的な防衛術を叩き込む。

—

1. なぜJWTは「署名なし」を許してしまったのか

JWTのヘッダーにある alg(アルゴリズム)フィールドは、本来、署名の検証方法を指定するものだ。しかし、設計の初期段階で「デバッグ用」として紛れ込んだ none という値が、全ての悪夢の始まりだった。

alg: none 攻撃の正体

攻撃者は、トークンのヘッダーを以下のように書き換える。

{
  "alg": "none",
  "typ": "JWT"
}

この状態で、ペイロードを {"sub": "admin", "role": "superuser"} のように改ざんし、末尾の署名部分を空にして送信する。もしサーバー側の検証ライブラリが「algが指定されていないから検証をスキップしよう」と判断すれば、即座に管理者権限が奪取される。

対策: サーバー側で受け取ったトークンの alg を信用してはならない。ホワイトリスト方式で「使用して良いアルゴリズム」をハードコードし、それ以外が指定されたら即座に例外を投げるべきだ。

—

2. 鍵の混同攻撃(Key Confusion Attack)の深淵

これはさらにタチが悪い。非対称暗号(RSA)と対称暗号(HMAC)の仕組みの差を突いた攻撃だ。

  • RSA(公開鍵暗号): 秘密鍵で署名し、公開鍵で検証する。
  • HMAC(共通鍵暗号): 共有鍵で署名し、同じ共有鍵で検証する。

攻撃者は、サーバーが公開鍵を使ってJWTを検証していることを知ると、ヘッダーを alg: HS256 に書き換える。するとサーバーは「公開鍵」を「HMACの共有鍵」として読み込み、署名を検証しようとする。公開鍵をファイルとして保存している場合、そのバイト列をHMACの鍵として利用できてしまうため、攻撃者は公開鍵を使って署名を偽造できる。

—

3. 実践:セキュアな実装コード(Node.js / jsonwebtoken)

多くのエンジニアがやりがちなのが、jwt.verify(token, secretOrPublicKey) を深く考えずに使うことだ。これでは alg の強制ができない。

以下は、アルゴリズムを明示的に固定した、絶対に守るべき実装例だ。

const jwt = require('jsonwebtoken');

// 悪い例: アルゴリズムを固定していない
// jwt.verify(token, publicKey); 

// 良い例: アルゴリズムを明示的に固定する
try {
  const decoded = jwt.verify(token, publicKey, {
    algorithms: ['RS256'] // ここでRS256以外を弾く
  });
  console.log("検証成功:", decoded);
} catch (err) {
  // 攻撃やトークン期限切れを検知
  console.error("不正なトークンまたはアルゴリズム:", err.message);
}

—

4. インフラ・環境レベルでの防御

コードだけで解決しようとするな。セキュリティは多層防御だ。

WAFでの防衛

Web Application Firewall(WAF)の設定で、JWTのヘッダーを検査するのが有効だ。例えばNginxのリバースプロキシ層で、怪しいJWTの構造を弾くこともできるが、最も確実なのは、API Gatewayレベルで alg: none を含むリクエストを拒絶するポリシーを適用することだ。

クラウドIAM・鍵管理の鉄則

RS256 を使う場合、公開鍵をコードに直書きするな。AWS KMSなどの鍵管理サービスを使い、プログラムが「秘密鍵を知らない」状態を保て。

  • 秘密鍵: 署名を行う認証サーバーのみがアクセス可能にする。
  • 公開鍵: 認証サーバーから定期的に取得するか、JWKS(JSON Web Key Set)エンドポイント経由で配布する。

—

後輩エンジニアへ贈る言葉

「ライブラリのデフォルト設定だから大丈夫だろう」という慢心が、最大の脆弱性だ。

1. alg はホワイトリスト化せよ: サーバーサイドで許容するアルゴリズムを必ず制限する。
2. 鍵の型を厳格に: RS256(非対称)を使っているなら、HMAC系の鍵が混入しないよう検証関数を厳格に分離せよ。
3. ライブラリを最新に: 著名なライブラリ(jsonwebtoken等)は、過去の脆弱性から学び、algの強制検証機能を持っている。常に最新版を追いかけろ。

セキュリティとは、技術的なコードを一行書くこと以上に、「最悪の事態を常に想定する」というエンジニアの姿勢そのものだ。今日から自分の書いたコードを、もう一度 alg の観点で見直してくれ。健闘を祈る。

コメント

タイトルとURLをコピーしました