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

JWTの深淵:alg: noneと鍵混同攻撃から読み解く「実装の死角」

エンジニア諸君、JWT(JSON Web Token)という「現代の通行手形」を、君たちは本当に制御できているか?

多くの開発者は、JWTを単なる「Base64でエンコードされた便利なトークン」と認識しているが、それは大きな誤りだ。JWTは、暗号学的な検証ロジックをアプリケーション層に丸投げする、極めて危険な設計上の脆弱性を孕んだ仕様であることを忘れてはならない。今日は、JWTの実装における「初歩的だが致命的な地雷」であるalg: noneと、鍵混同攻撃(Key Confusion Attack)について、泥臭いアーキテクチャの観点から解剖する。

—

1. なぜalg: noneが許されるのか:仕様という名の「罠」

JWTの仕様(RFC 7519)には、デバッグ目的を装ったnoneというアルゴリズムが存在する。これは署名を行わないことを意味し、ヘッダーに{"alg": "none"}と記述するだけで検証をスキップできる。

攻撃者は、このヘッダーを書き換え、ペイロードを改ざんし、署名部分を空にすることで、認証を無効化する。これを許すライブラリや実装は、もはや「鍵をかけない玄関」を運用しているに等しい。

なぜこれが防げないのか?

多くの開発者は検証ロジックにおいて、「署名が有効か」を確認する前に「ヘッダーのアルゴリズムを確認する」という手順を踏む。もしライブラリの設定が不適切であれば、verify()メソッドがnoneを正当なアルゴリズムとして受け入れてしまう。

対策の鉄則:
検証ロジックの最上段で、ホワイトリスト以外のアルゴリズムを即座に拒絶せよ。

// 不適切な検証例:algを信頼してしまっている
const decoded = jwt.verify(token, secret); 

// 対策例:期待するアルゴリズムを明示的に強制する
const verified = jwt.verify(token, secret, {
  algorithms: ['RS256'] // RS256以外は問答無用で弾く
});

—

2. 鍵混同攻撃(Key Confusion Attack):RSAの公開鍵がHMACの秘密鍵に化ける瞬間

これは、暗号理論の基礎を逆手に取った、非常に巧妙な攻撃だ。

RSA(非対称暗号)では「公開鍵」を使って署名を検証し、HMAC(対称暗号)では「秘密鍵」を使って署名を検証する。しかし、多くのライブラリは、同じ検証関数(例えばverify())の中で、引数として渡された鍵を「アルゴリズムに応じて適切に解釈」しようと試みる。

攻撃者は以下を狙う:
1. 攻撃の手順: サーバーが公開鍵(PEM形式)をファイルシステムや証明書ストアに保持していることを特定する。
2. すり替え: 攻撃者は、署名アルゴリズムをHS256(HMAC)に変更し、署名値に「RSAの公開鍵そのもの」をHMACの「共有鍵」として流し込む。
3. 検証の破綻: ライブラリは、HS256と見なして、渡された「RSA公開鍵」をHMACの鍵として署名を計算する。もしサーバー側の公開鍵を知っていれば、攻撃者は誰でも正しい署名を生成できてしまう。

アーキテクチャ上の防衛ライン

この脆弱性を防ぐ鍵は、「暗号アルゴリズムと鍵のコンテキストを分離すること」に尽きる。

// 悪い例:同じ検証関数をアルゴリズム不定で使い回す
// $keyには公開鍵が入っているが、攻撃者が alg: HS256 を送ると、
// ライブラリは $key を HMAC の秘密鍵として扱ってしまう。
JWT::decode($token, $key, ['HS256', 'RS256']); 

// 良い例:厳密な型と鍵の分離
// RS256なら公開鍵オブジェクトを、HS256なら環境変数から取得した厳密な秘密鍵を渡す
if ($header['alg'] === 'RS256') {
    $publicKey = openssl_pkey_get_public(file_get_contents('public.pem'));
    JWT::decode($token, $publicKey, ['RS256']);
} else {
    throw new Exception("許可されていないアルゴリズムです");
}

—

3. 次世代の防衛:耐量子暗号と生成AI時代への布石

今後、量子コンピュータの台頭により、現在主流のRSAやECCは計算量的に無力化されるリスクがある。特にJWTのような署名技術は、将来的に「署名の偽造」が容易になる可能性がある。

1. 耐量子暗号(PQC)への準備:
現在、JWTの仕様でもEdDSA(Edwards-curve Digital Signature Algorithm)のような、より強固なアルゴリズムへの移行が進んでいる。これらは将来的な耐量子アルゴリズムへの橋渡しとなる。
2. 生成AIによるプロンプトインジェクションへの防御:
JWTのペイロードに、AIが解析するような機密データを含めることは避けろ。AIがJWTのデータを解釈する際、sub(サブジェクト)やroles(権限)フィールドがプロンプトインジェクションの媒介になるリスクを考慮し、AI側のガードレイル(入力値のサニタイズ)をJWTの検証レイヤーとは別に設けるべきだ。

結びに:セキュリティは「仕様の行間」にある

JWTの脆弱性の多くは、RFCの不備というよりは、「便利すぎるライブラリの抽象化」を盲信した開発者の慢心から生まれる。

君たちが設計すべきは、JWTが届いた瞬間に「こいつは悪意があるかもしれない」と疑うレイヤーだ。アルゴリズムをハードコードし、鍵のストレージを分離し、検証のたびに「この鍵はこのアルゴリズムのためにあるのか?」を自問自答せよ。

サイバーセキュリティの世界では、最も退屈な「検証作業」こそが、システムの寿命を決定づけるのだ。健闘を祈る。

コメント

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