Hello there, ('ω')ノ
🛡 JWTの仕組み再確認
JWTには以下の3つの部分があります:
- ヘッダー:アルゴリズムの情報など
- ペイロード:ユーザー名や権限などの情報
- 署名:改ざんされていないことを確認するもの
この署名は「サーバーの秘密鍵」を使って作られており、サーバーが検証することで改ざんを防止できます。
💥 脆弱性:署名が検証されていない
ある日開発者がこんなコードを書いたとします:
const token = req.cookies.token; const payload = jwt.decode(token); // 署名検証してない!
この場合、トークンの中身は何を書いても通ってしまうため、以下のように改ざんが可能です:
{ "username": "carlos", "isAdmin": true }
これをJWTとしてBase64エンコードしてサーバに送ると…
username
を他人に変える → 他人のアカウントに不正ログインisAdmin
をtrue
に変える → 管理者に昇格
📛 よくあるミス:verify() と decode() の混同
多くのJWTライブラリには次の2つの関数があります:
verify()
→ 署名付きのトークンを正しく検証decode()
→ ただBase64をデコードするだけ(検証しない)
verify()を使わずにdecode()だけ使っていると100%アウトです。
🧪 実験:JWT署名を無視して偽造トークンでログイン!
- トークンをデコードして中身を見てみる
sub
やisAdmin
の値を好きなように変更- ヘッダーを
{"alg":"none"}
に書き換え(署名不要にする) - 再エンコードして送信 → アプリがそのまま受け入れる
🔐 対策方法
対策 | 説明 |
---|---|
✅ 必ず verify() を使用 |
decode()は使わず署名検証を必ず行う |
🔒 強力な秘密鍵を使用 | 推測されにくいランダムなキーにする |
🚫 alg: none を許可しない |
noneアルゴリズムは絶対に無効化する |
🔄 ライブラリの更新 | 脆弱性のある旧バージョンを使わない |
Best regards, (^^ゞ