メインコンテンツへスキップ
友田 陽大
実践Webハッキング技法
セキュリティ
ホワイトハッカー
JWT
脆弱性診断
Webセキュリティ

JWT攻撃の完全攻略【2026】alg:none・鍵ブルートフォース・アルゴリズム混同・jwk/jku/kid注入 — 公式ドキュメント忠実版

JWT(JSON Web Token)攻撃の手法を、PortSwigger Web Security Academyに忠実に深掘り。署名検証の不備(任意署名の受理・alg:none)、HS256の弱い秘密鍵のhashcatブルートフォース、jwk/jku/kidヘッダ注入、RS256→HS256のアルゴリズム混同(鍵混同)攻撃の仕組みと、アルゴリズム固定・厳格な署名検証・jkuホスト許可リストによる根本対策までを、自分のラボ限定の実例で解説します。

公開日
読了時間
7分
著者
友田 陽大
シェア

JWT(JSON Web Token)は、現代のSPAやマイクロサービスの認証・セッション管理で広く使われます。だからこそ、JWTの検証を一つ間違えると、認証が丸ごと崩壊します。PortSwigger が言う通り「JWTベースの仕組みの安全性は、暗号署名に大きく依存」しており、攻撃の大半はその署名検証の手抜きを突きます。本記事は、その攻撃手法を公式に忠実に解説します。

絶対の前提: 全手順は 合法ラボ または許可スコープでのみ。他人のトークンの偽造・なりすましは、検証目的でも無許可なら不正アクセスです(→ 法律ガイド)。地図は ピラー。JWTを含むトークン設計の基礎は IDトークンとアクセストークンの違い も参照。


1. JWTの構造 — 3つのパート

JWTは header.payload.signature の3つをドット区切りで base64url エンコードしたものです。

eyJhbGciOiJIUzI1NiJ9 . eyJzdWIiOiJ3aWVuZXIifQ . <署名>
└─ header ────────┘   └─ payload ──────────┘
{"alg":"HS256"}        {"sub":"wiener","role":"user"}
  • header:署名アルゴリズム(alg)などのメタ情報。
  • payload:クレーム(誰か・権限・有効期限など)。Base64は暗号化ではないので、誰でも中身を読める。
  • signature:header+payload を鍵で署名したもの。改ざん検出はここだけが頼り

つまり、署名検証が甘ければ、payloadを "role":"admin" に書き換え放題になります。


2. 署名検証の不備を突く

2.1 署名を検証していない / 任意署名の受理

開発者が「デコード」と「検証」を混同し、署名を検証せずにpayloadを信用しているケース。payloadを書き換えるだけで通ります。

# payload の "sub":"wiener" を "sub":"administrator" に書き換えて送るだけで通る
# (Burp の JWT Editor 拡張でワンクリック改ざん→送信できる)

2.2 alg:none

JWS仕様には「署名なし(alg:none)」が存在します。サーバーがこれを受理すると、署名を空にしてpayloadを自由に改ざんできます。

# header を {"alg":"none"} にし、署名部分を空にする
eyJhbGciOiJub25lIn0 . eyJzdWIiOiJhZG1pbmlzdHJhdG9yIn0 .
                                                       └─ 署名は空

単純な none が弾かれても、PortSwigger が指摘する通り NonenOnE・予期しないエンコードといった難読化で検証フィルタを抜けることがあります。


3. 弱い秘密鍵のブルートフォース(HS256)

HMAC系(HS256)は**「任意の文字列」を秘密鍵**にします。鍵が弱い/既定値だと、hashcat で割れます。

# JWTを辞書攻撃(-m 16500 が JWT モード)。割れた鍵が標準出力に出る
hashcat -a 0 -m 16500 jwt.txt /usr/share/wordlists/jwt.secrets.list

# 鍵が判明したら、任意のpayloadを「正規に」署名できる = 完全な認証バイパス
# 例: {"sub":"administrator"} を割れた鍵で署名して送る

鍵が割れたら終わりです。だから秘密鍵は十分に長く・ランダムでなければなりません(弱い既定鍵の流用が事故の典型)。応用暗号と鍵管理の原則は パスワードハッシュ・暗号・鍵管理ガイド を参照。


4. ヘッダ・パラメータ注入(jwk / jku / kid)

JWT仕様は、署名検証に使う鍵をヘッダで指定する仕組みを持ちます。サーバーがこれを無検証で信用すると、攻撃者の鍵で検証させられます。

パラメータ意味攻撃
jwk公開鍵をトークン内に直接埋め込む自分の鍵ペアで署名し、公開鍵をjwkに埋めて送る
jku鍵セット(JWK Set)のURLを指す攻撃者サーバーのJWK SetをURLに指定
kid使う鍵のID(ファイル/DB参照に使われがち)パストラバーサル(../../dev/null)やSQLiで鍵を操作
# jwk 注入の例(header に自前の公開鍵を埋め、その秘密鍵で署名)
{"alg":"RS256","typ":"JWT","jwk":{"kty":"RSA","n":"<攻撃者の公開鍵>","e":"AQAB"}}

# kid をパストラバーサルに:既知内容のファイルを鍵に使わせ、署名を予測可能にする
{"alg":"HS256","kid":"../../../../../../dev/null"}
# /dev/null は空 → 鍵が空文字列になり、攻撃者が署名を作れる

5. アルゴリズム混同(鍵混同)攻撃 — RS256 → HS256

最も巧妙なのが**アルゴリズム混同(algorithm confusion / key confusion)**です。サーバーがRS256(非対称:公開鍵で検証・秘密鍵で署名)を想定しているのに、検証時にalgを固定していないと成立します。

仕組み:

  1. RS256の公開鍵は誰でも入手できる(JWKエンドポイントや証明書から)。
  2. 攻撃者は algHS256(対称)に変えたトークンを作る。
  3. そのトークンを、公開鍵の文字列を「HMACの秘密鍵」として署名する。
  4. サーバーは「HS256だな」と判断し、手元の公開鍵をHMAC鍵として検証 → 一致してしまう。
# 概念:本来 RS256 のサーバーへ、HS256 で署名したトークンを送る
# 署名鍵 = サーバーのRSA「公開」鍵(PEM文字列そのもの)
header  = {"alg":"HS256"}
payload = {"sub":"administrator"}
signature = HMAC-SHA256(base64(header)+"."+base64(payload), <RSA公開鍵PEM>)

公開鍵は秘密でないため、攻撃者は正規に「見える」トークンを偽造できる。これが鍵混同の怖さです(Burpの JWT Editor でPoC可能)。


6. 【守る側】根本対策

攻撃の構造がわかれば、防御は明快です。PortSwigger の推奨に沿います。

// ✅ 検証時にアルゴリズムを「固定」する(最重要)。none も他algも受け付けない
import { jwtVerify } from "jose";

const { payload } = await jwtVerify(token, publicKey, {
  algorithms: ["RS256"], // ← 許可リスト。これが無いと alg 混同/none を許す
  issuer: "https://auth.example",
  audience: "https://api.example",
});

設計原則:

  • アルゴリズムをサーバー側で固定(許可リスト)。alg:none を拒否し、トークンのalgを信用しない。これだけで alg混同・none の大半を封じる。
  • 検証は必ず行う:「デコード」関数(decode)と「検証」関数(verify)を混同しない。
  • jku/jwk のホストを許可リスト化(任意URLの鍵を信用しない)。kid はパストラバーサル/SQLi 対策を施す。
  • 秘密鍵は長くランダムに(HS256の弱鍵を避ける)。鍵のローテーションを設計。
  • 実績ある最新ライブラリを、ドキュメント通りに使う(自前実装しない)。jose / jsonwebtoken 等。
  • 有効期限(exp)と失効:短い有効期限 + リフレッシュトークン + 失効リストで、漏洩時の被害を限定。
  • 保存場所:XSSでの窃取を避けるため、ブラウザでは HttpOnly Cookie を検討(→ XSS対策)。

認証基盤としての堅牢な設計(Cognito/Auth0/Clerk/Supabase Authの選定と、RS256のJWKS検証)は 認証プラットフォーム選定Cognito JWT RS256検証 で詳説しています。


7. まとめ

  • JWTの安全性は署名検証に全依存:検証の手抜き(未検証・alg:none・甘い検証)が主な穴。
  • 弱鍵はhashcatで割れる:HS256の鍵は長くランダムに。
  • ヘッダ注入:jwk/jku/kid をサーバーが無検証で信用すると攻撃者の鍵で通る。
  • アルゴリズム混同:alg未固定だと、公開鍵をHMAC鍵にされ偽造される。
  • 根本対策:アルゴリズム固定 + 必ず検証 + jku/kid厳格化 + 長鍵 + 最新ライブラリ + exp/失効。

次は、ログイン機構そのものを狙う 認証の脆弱性の完全攻略 へ。


参考(公式一次情報)

友田

友田 陽大

経済産業大臣賞 受賞プロダクト開発者。TypeScript + Python + AWS で、SaaS・業界DX・ 実用レベルの生成AI(RAG)を、要件定義からインフラ・運用まで一人で完遂します。

この攻撃、あなたのアプリで再現されたら?

Webアプリの脆弱性診断・ペネトレーションテストを承ります

この記事で扱った SQLi・XSS・SSRF・JWT・認証・SSTI といった攻撃を、あなたのアプリで実際に再現・診断し、設計から修正するところまで承ります。攻撃の手筋を知る者だけが、設計段階で『どこが破れるか』を先回りで潰せます。まず無料OSSで現状を可視化してからでも構いません。

プロジェクト単位(請負)・技術顧問のどちらにも対応可能です。まずは30分の無料技術相談から。

あわせて読みたい