JWTの「魔法の鍵」が悪用される?泥棒に玄関を開けさせないためのセキュリティ防衛術
こんにちは!現場でセキュリティと格闘していると、「なぜこんな単純なミスが起きるのか?」と頭を抱えたくなるような脆弱性にしばしば遭遇します。今回は、Web開発で欠かせないJWT(JSON Web Token)という「デジタル通行手形」に潜む、ちょっと恐ろしい「鍵のすり替え」についてお話しします。
「JWTって何?」という方も、家の鍵をイメージしてください。JWTは、あなたが「誰であるか」を証明するための鍵付きの封筒です。しかし、この封筒の仕組みを悪用する泥棒は、封筒を破るのではなく、「封筒のルールそのもの」を書き換えて、中身を自由に改ざんしてきます。
一歩ずつ、この仕組みを紐解いていきましょう。
—
1. なぜJWTが狙われるのか?「署名」というルールを逆手に取る
JWTは、通常3つのパーツからできています。
1. ヘッダー(どんな鍵で封をしたか書いている)
2. ペイロード(あなたの名前や権限などのデータ)
3. 署名(この内容が改ざんされていないことを証明するハンコ)
本来、この「署名」があるからこそ、サーバーは「お、これは本物だ」と信用できます。しかし、攻撃者はヘッダーの部分をいじり始めます。
攻撃その1:alg: none 攻撃(鍵なんていらないよ、と言い張る)
これが最も原始的な攻撃です。JWTのヘッダーにある alg(アルゴリズム)という項目を、勝手に none に書き換えてしまうのです。
- 例え話: 「この封筒には鍵をかけていません。だから中身もチェックしないでね!」というメモを勝手に貼り付けるようなものです。
- なぜ通るのか: プログラム側が「
alg: noneなら署名検証をスキップしちゃえ!」と実装していると、泥棒は署名なしで自由に中身を書き換え、サーバーに侵入できてしまいます。
—
2. 鍵のすり替え:HMACと公開鍵の「勘違い」
次に紹介するのは、少し巧妙な「鍵混同攻撃(Key Confusion Attack)」です。これは、非対称鍵暗号(公開鍵と秘密鍵を使う方式)を利用しているシステムが狙われます。
どんな仕組み?
- 本来のルール: サーバーは「秘密鍵(自分だけが持つ鍵)」で署名し、クライアントは「公開鍵(誰でも持てる鍵)」で中身が正しいか確認する。
- 攻撃手法: 攻撃者は、公開鍵を使って署名を検証するはずのサーバーに、「このトークンは秘密鍵じゃなくて、公開鍵でチェックしてね(HMAC形式でね)」と指示を出します。
サーバーがうっかりこの指示に従うと、「公開鍵そのものを、秘密鍵の代わりに使って署名を検証」し始めます。攻撃者は公開鍵を知っているので、偽のトークンを作って署名を生成できてしまうのです。
—
3. 実践!どうやって防げばいいの?
対策はシンプルですが、実装時に徹底する必要があります。以下のポイントを押さえてください。
対策①:アルゴリズムを厳格に指定する
ライブラリを使う際、alg をサーバー側で固定してください。「何が来てもOK」ではなく、「これだけは許す」というホワイトリスト方式です。
// Node.js (jsonwebtokenライブラリ) の例
jwt.verify(token, publicKey, {
// ここでアルゴリズムを明示的に指定!noneや他の方式を排除します
algorithms: [‘RS256’]
}, (err, decoded) => {
if (err) {
// 検証失敗!怪しいトークンです
console.error(“不正なトークンが検出されました”);
}
});
対策②:鍵の種類を混同させない
公開鍵を使う方式(RSAなど)と、共通鍵を使う方式(HMACなど)を明確に分け、ライブラリが自動的にアルゴリズムを判断するような実装を避けます。
- 避けるべき実装: トークン内のヘッダー情報のみを信頼して検証ロジックを切り替えること。
- 推奨の実装: 「このエンドポイントは絶対にRS256で検証する」とサーバー側でハードコーディングする。
—
現場のエンジニアへ:今日からできる一歩
セキュリティ対策は「完璧な城を築くこと」ではありません。「泥棒が一番嫌がる防犯ベルを仕掛けておくこと」です。
1. JWTのライブラリは最新か? 古いライブラリは none を許容してしまうバグが残っていることがあります。
2. ログを監視しているか? 異常なアルゴリズム指定が来た瞬間、アラートを飛ばせるようにしましょう。
3. 「信用しない」を前提にする: ユーザーが送ってきたトークンの中身(ヘッダー含む)を、そのまま検証関数に渡さないでください。
JWTは便利ですが、その便利さは「正しい実装」という土台の上で初めて成り立ちます。今日紹介した「鍵のすり替え」は、少しの注意で必ず防げます。ぜひ、あなたのプロジェクトのコードを見直してみてくださいね!
もし何か不明点や、「うちのコードは大丈夫かな?」といった相談があれば、いつでも聞いてください。一緒に安全なシステムを作り上げていきましょう!
コメント