現場のエンジニア諸君、お疲れ様。今日もどこかで認証トークンが不正に書き換えられ、誰かが管理者権限を奪取されているかもしれない。
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 の観点で見直してくれ。健闘を祈る。
コメント