なぜ「JWTの鍵」は、家の鍵と同じくらい慎重に扱うべきなのか?
こんにちは!セキュリティの世界へようこそ。今日は、Webアプリ開発でよく耳にする「JWT(JSON Web Token)」についてお話しします。
「JWT? ああ、ログインに使ってるあれね」と思ったあなた。その認識、半分正解ですが、半分は少し危険かもしれません。JWTはWeb上の「通行手形」のようなものですが、使い方を間違えると、泥棒に合鍵を渡しているのと同じ状況になってしまうんです。
今日は、JWTを安全に運用するための「署名(サイン)」の仕組みと、絶対に守るべきルールを、身近な防犯に例えて紐解いていきましょう。
—
1. JWTは「封筒付きの通行手形」
JWTが何なのか、イメージしてみてください。これは、中に「ユーザーID」や「権限」という情報が入った、封蝋(ふうろう)が押された手紙です。
サーバー(受付)は、その手紙が本物かどうかを「封蝋の形」で判断します。もし、誰かが中身を書き換えても、封蝋を壊して押し直すことはできません。この「封蝋を押す作業」こそが署名(Signature)です。
署名のアルゴリズム:HS256とRS256の違い
ここで重要なのが、封蝋の「押し方(アルゴリズム)」です。
- HS256 (共通鍵方式): 家の合鍵を、自分と家族(サーバー)が「同じもの」を持っている状態です。鍵が一つしかないため、もし誰かに鍵を盗まれたら、即座に家全体(システム全体)が危機にさらされます。
- RS256 / ES256 (公開鍵方式): 「鍵」と「鍵穴」を分ける仕組みです。あなたは「鍵穴(公開鍵)」を誰にでも見せますが、鍵を閉めるための「特別なペン(秘密鍵)」は金庫に隠しておきます。これなら、鍵穴が知られても家の中には入れません。
結論から言うと、HS256はリスクが高すぎるため、現代の開発ではRS256やES256への移行が必須です。
—
2. 泥棒が狙う「盲点」:alg: none 攻撃
開発の現場で一番怖いのが、攻撃者が「署名なんていらないよ」と嘘をつく「alg: none 攻撃」です。
これは、JWTのヘッダー部分に "alg": "none" と書き込んでサーバーに送りつける手法です。「この手紙には署名がありませんよ」とサーバーを騙し、署名のチェックをすり抜けて中身(管理者権限など)を改ざんしようとします。
対策はシンプルです。
サーバー側でJWTを読み取る際、「アルゴリズムが指定したものと一致するか」を厳格にチェックするロジックを必ず入れてください。
—
3. 実践:安全な検証ロジックを実装する
Node.js(jsonwebtokenライブラリ)を例に、安全な実装を見てみましょう。
const jwt = require(‘jsonwebtoken’);
// 公開鍵を読み込む(秘密鍵はサーバー内に隠しておくこと!)
const publicKey = fs.readFileSync(‘public.pem’);
// トークンを検証する関数
function verifyToken(token) {
try {
// 【重要】algorithmsを指定することで、none攻撃や意図しない暗号方式をブロックします
const decoded = jwt.verify(token, publicKey, {
algorithms: [‘RS256’] // RS256以外は受け付けない!
});
console.log(“本人確認完了!:”, decoded);
return decoded;
} catch (err) {
console.error(“不正なトークンです:”, err.message);
return null;
}
}
このコードのポイント
1. algorithms: ['RS256']: これを指定することで、「もし攻撃者が alg: none を送ってきても、このコードはエラーを吐いて拒絶する」という強力な盾になります。
2. 鍵の分離: 秘密鍵は環境変数やKey Management Service(KMS)で厳重に管理し、ソースコードに直書きなんて絶対にしないでくださいね!
—
4. セキュリティ担当からのアドバイス:一歩ずつ着実に
「難しいことが多そう…」と感じたかもしれません。でも大丈夫です。まずは今のプロジェクトで、以下の3つを確認するだけで、あなたのアプリは劇的に強固になります。
1. アルゴリズムを確認する: 現在HS256を使っていたら、運用を変えてRS256やES256への切り替えを検討しましょう。
2. アルゴリズムを固定する: 検証ロジックで必ず algorithms オプションを指定し、許可された方式以外を拒否してください。
3. 鍵は隠す: 秘密鍵をGitにコミットしていないか、今すぐ確認してください。
セキュリティは、一度にすべて完璧にする必要はありません。このように「一つずつ穴を塞いでいく」ことが、何よりの防御になります。
さあ、あなたのコードをもっと安全に、もっと強く。一緒に頑張りましょう!また何かあれば、いつでも相談してくださいね。
コメント