Shikata Ga Nai

Private? There is no such things.

JWT署名検証ミスの悪用

Hello there, ('ω')ノ

🛡 JWTの仕組み再確認

JWTには以下の3つの部分があります:

  1. ヘッダー:アルゴリズムの情報など
  2. ペイロード:ユーザー名や権限などの情報
  3. 署名:改ざんされていないことを確認するもの

この署名は「サーバーの秘密鍵」を使って作られており、サーバーが検証することで改ざんを防止できます。


💥 脆弱性:署名が検証されていない

ある日開発者がこんなコードを書いたとします:

const token = req.cookies.token;
const payload = jwt.decode(token); // 署名検証してない!

この場合、トークンの中身は何を書いても通ってしまうため、以下のように改ざんが可能です:

{
    "username": "carlos",
    "isAdmin": true
}

これをJWTとしてBase64エンコードしてサーバに送ると…

  • username を他人に変える → 他人のアカウントに不正ログイン
  • isAdmintrue に変える → 管理者に昇格

📛 よくあるミス:verify() と decode() の混同

多くのJWTライブラリには次の2つの関数があります:

  • verify() → 署名付きのトークンを正しく検証
  • decode() → ただBase64をデコードするだけ(検証しない)

verify()を使わずにdecode()だけ使っていると100%アウトです。


🧪 実験:JWT署名を無視して偽造トークンでログイン!

  1. トークンをデコードして中身を見てみる
  2. subisAdminの値を好きなように変更
  3. ヘッダーを {"alg":"none"} に書き換え(署名不要にする)
  4. 再エンコードして送信 → アプリがそのまま受け入れる

🔐 対策方法

対策 説明
✅ 必ず verify() を使用 decode()は使わず署名検証を必ず行う
🔒 強力な秘密鍵を使用 推測されにくいランダムなキーにする
🚫 alg: none を許可しない noneアルゴリズムは絶対に無効化する
🔄 ライブラリの更新 脆弱性のある旧バージョンを使わない

Best regards, (^^ゞ