JWT authentication bypass via jku header injection
概要
JWTヘッダーの jku (JSON Web Key Set URL) パラメータを悪用し、攻撃者が用意した公開鍵を参照させることで、任意のペイロード(管理者権限など)を持つ偽造トークンの署名をサーバに検証・受理させる攻撃。
調査
- JWTヘッダーに
jkuパラメータが存在するか、または追加してリクエストを送った際にサーバがそれを受け入れるか。 -
jkuに外部URLを指定した際、サーバがそのURLに対してHTTPリクエストを行うか(SSRFの側面)。
攻撃手順
- RSA鍵ペアの生成: 攻撃者自身で新しいRSAの秘密鍵と公開鍵のペアを生成する(BurpのJWT Editor拡張機能などを使用すると容易)。
-
JWK Setの用意: 生成した公開鍵をJWK形式(JSON Web Key Set)にし、攻撃者が制御可能なサーバ(Exploit Serverなど)に配置する。
-
JWKSの内容例(公開鍵情報のみで良い):
{ "keys": [ { "kty": "RSA", "e": "AQAB", "use": "sig", "kid": "my-key-id", "alg": "RS256", "n": "<base64url-encoded-modulus>" } ] }
-
JWKSの内容例(公開鍵情報のみで良い):
-
JWTの改ざん:
-
Header:
jkuパラメータを追加・変更し、手順2で用意したURLを指定する。kidパラメータを手順2のkidと一致させる。 -
Payload:
subやusernameなどを管理者のもの(例:administrator)に書き換える。
-
Header:
- 署名の生成: 手順1で生成した秘密鍵を使用して、改ざんしたJWTに署名を行う。
- リクエスト送信: 生成されたJWTを用いてアクセスする。
対策
-
jkuヘッダーの無効化: 基本的にクライアント側が指定したURLを信頼して鍵を取得する設計は避ける。 -
URLのホワイトリスト検証: どうしても
jkuが必要な場合、指定されたURLが信頼できるドメイン(自社サーバなど)であるかを厳格に検証する。 - 署名検証の強制: ライブラリの設定で、信頼できる鍵以外での署名検証を許可しないようにする。
クリアするまでにかかった時間
20m
所感
jwk ヘッダーインジェクションではトークン内に直接鍵を埋め込んだが、jku では「鍵の置き場所(URL)」を指定するという違いがある。サーバが「ヘッダーに書かれたURLを無条件に信じて鍵を取りに行き、その鍵で検証してしまう」という挙動が脆弱性の本質であると理解した。
メモ
-
JKU (JSON Web Key Set URL) とは
- JWTの署名を検証するための「公開鍵セット(JWK Set)」が配置されているURLを指定するヘッダーパラメータ。
- 規格上(RFC 7515)定義されているが、実装する際はセキュリティリスクが高いため注意が必要。
-
jwk header injection との違い
- jwk: 公開鍵そのもの(データ)をヘッダーに埋め込む。
- jku: 公開鍵がある場所(URL)をヘッダーに記述する。
- どちらも「攻撃者が用意した鍵をサーバに信頼させる」というゴールは同じ。
-
攻撃の成立条件
- サーバが
jkuヘッダーを処理する設定になっていること。 - サーバが
jkuで指定されたURLのドメインやパスを適切に検証(ホワイトリストチェック等)していないこと。
- サーバが