ssecutils
Security / Browser-native guide

JWT のよくあるセキュリティ問題

alg=none、アルゴリズム混同、弱い秘密鍵、payloadの過信など、JWTで起きがちな事故を実務目線で整理します。

6Zero tracking reading surface

はじめに:JWT の落とし穴

JWT(JSON Web Token)は API 認証の事実上の標準として広く使われていますが、正しく使わないと深刻なセキュリティ問題に直結します。「ライブラリに任せれば安全」と思いがちですが、JWT に固有の罠は意外と多く、一度実装した認証基盤が侵入経路になる事例は珍しくありません。

この記事では、初学者が JWT を扱うときに知っておきたい 5つの典型的な問題 と、その対策をまとめます。

JWT の構造(おさらい)

JWT は Header.Payload.Signature の3パート構成で、それぞれが Base64URL でエンコードされています。

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyMSJ9.SflKxwRJSMeKKF2QT4...
└── Header ──┘└── Payload ──┘└─── Signature ───┘

Header と Payload は単なる Base64URL なので誰でも読めます(後述)。Signature だけが、発行者の鍵を知っている人にしか作れません。

問題1: alg=none 攻撃

JWT の Header には alg(アルゴリズム)クレームがあり、検証側のライブラリはこの値を見てアルゴリズムを切り替えます。ここで 攻撃者が algnone に書き換える と、署名なしで通ってしまうライブラリがありました。

{"alg":"none","typ":"JWT"}.{"sub":"admin"}.    ← 署名空欄

2015年の有名な脆弱性で、当時の多くのライブラリが影響を受けました。対策 は単純で、検証側で受け入れる alg をハードコードで限定することです。「Header の alg を信頼する」のが間違いの始まりです。

問題2: アルゴリズム混同(RS256 → HS256)

RS256(RSA 公開鍵署名)で運用しているサービスを攻撃者が見つけたとき、algHS256(HMAC)に書き換えて、公開鍵をそのまま HMAC の秘密鍵として使う 攻撃です。

多くのライブラリが「RS256 用に渡された公開鍵」を「HS256 の検証鍵」としてそのまま受け入れてしまうのが問題でした。公開鍵は誰でも入手できるので、攻撃者は任意のトークンを生成できてしまいます。

対策: 検証時に「このトークンは RS256 でなければならない」と明示する。verify(token, key, { algorithms: ['RS256'] }) のように、許可するアルゴリズムを必ず指定してください。

問題3: 弱い HMAC 秘密鍵

HMAC(HS256/384/512)を使う場合、秘密鍵が短すぎる・推測しやすいとブルートフォースで割られます。secretjwt-key のような語、辞書単語、12文字以下などは数分〜数時間で破られる可能性があります。

  • 長さ: HS256 なら 32 バイト(256 bit)以上を推奨
  • 由来: crypto.randomBytes(32) 等の暗号学的乱数で生成し、環境変数や Secret Manager で管理
  • 禁止: ハードコード、Git にコミット、ドキュメントに掲載

問題4: Payload は誰でも読める

Base64URL は暗号化ではなく単なるエンコーディングです。JWT を持っている人なら誰でも Payload を復元できます。

echo "eyJzdWIiOiJ1c2VyMSIsInJvbGUiOiJhZG1pbiJ9" | base64 -d
{"sub":"user1","role":"admin"}

この事実を忘れて機密情報(クレジットカード番号、パスワード、社内識別子など)を Payload に入れると、トークンを取得した第三者にすべて見えてしまいます。Payload に入れていいのは「公開しても問題ない識別子」だけだと考えてください。

本当に秘匿が必要なら JWE(JSON Web Encryption)を使うか、そもそもセッション ID を使ってサーバー側にデータを保持する従来型の方が無難です。

問題5: トークンの取り消しが難しい

JWT は「有効期限が来るまで有効」が基本設計で、サーバー側で個別に無効化するのが構造的に苦手です。ユーザーがログアウトしても、トークン自体は exp まで使い続けられます。漏洩に気づいたときに即座に止めにくいのは大きな弱点です。

対策の方向性:

  • 有効期限を短く(数分〜1時間)し、リフレッシュトークンで延長する
  • サーバー側で取り消しリスト(denylist)を持って検証時に照合する(JWT らしさは犠牲になるが現実的)
  • 重要操作(決済・パスワード変更)の前にだけ再認証を要求する

防御策まとめ

  1. 検証時に許可する alg をハードコードで限定する
  2. iss, aud, exp, nbf必ず検証する
  3. HMAC の秘密鍵は 32 バイト以上の暗号学的乱数
  4. Payload に機密を入れない
  5. 短い有効期限 + リフレッシュ + 必要に応じて denylist
  6. JWT ライブラリは継続的にアップデートする

おわりに

JWT そのものは仕様としてよく設計されていますが、「使う側の油断が事故を生む」のがほとんどのケースです。実装を書くときは、信頼境界(誰が何を作れるか)を必ず意識してください。

本サイトの JWT Decoder は実際に署名検証もできるので、手元のトークンで alg 検証や鍵の強さを確認してみてください。

Tool companion

この記事と一緒に使えるツール

Related reading

関連記事