JWT の alg 検証
ある Web API は,受け取った JWT のヘッダの alg の値をそのまま信頼し,その値に従って署名検証のアルゴリズムを選ぶ実装になっている。本来この API は RS256(RSA 署名)で発行したトークンを検証しており,検証に使う RSA 公開鍵は公開されている。この実装に対する攻撃として,適切なものはどれか。
- アalg を none に変えても署名部が空になるだけで,サーバは必ず署名検証に失敗するので,改ざんしたトークンは拒否される。
- イalg を RS256 から HS256 に変え,公開鍵を HMAC の共有鍵として署名を計算すると,公開鍵で HMAC を検証する実装では正当な署名として受理され得る。
- ウJWT のペイロードは Base64URL エンコードされているので,攻撃者は内容を読めず,クレームの改ざんもできない。
- エRS256 の署名は RSA 秘密鍵がなければ作れないので,公開鍵が公開されていても,ヘッダの alg を書き換えるだけでは偽造したトークンは受理されない。
正解と解説を見る
正解 イ
この問題の基礎知識
- 署名付きの JWT(JWS 形式)は,ヘッダ・ペイロード・署名をそれぞれ Base64URL で符号化し,ピリオドで連結したものである。Base64URL は暗号化ではないので,誰でも内容を読める。
- JWT のヘッダの alg は署名のアルゴリズムを示す。RS256 は RSA の秘密鍵で署名して公開鍵で検証する方式,HS256 は同じ共有鍵で HMAC を計算して検証する方式であり,none は署名なしを意味する。
- HMAC は署名の生成と検証に同じ鍵を使うので,その鍵を知る者は誰でも正当な値を計算できる。
- トークンのヘッダは攻撃者が書き換えられるので,検証側は alg の値を信頼せず,受け入れるアルゴリズムを鍵ごとに固定して検証する必要がある。
アalg を none に変えても署名部が空になるだけで,サーバは必ず署名検証に失敗するので,改ざんしたトークンは拒否される。
alg を信頼する実装では,alg: none のトークンが署名検証なしで受理され得る(RFC 8725 2.1)。none なら必ず失敗するという思い込みで,alg を信頼する危険性を見落としている。
イalg を RS256 から HS256 に変え,公開鍵を HMAC の共有鍵として署名を計算すると,公開鍵で HMAC を検証する実装では正当な署名として受理され得る。正解
RSA 公開鍵は公開情報なので,それを HS256 の鍵として偽署名できる。サーバは alg を信頼せず,鍵ごとに想定するアルゴリズムを固定して検証すべきである。
ウJWT のペイロードは Base64URL エンコードされているので,攻撃者は内容を読めず,クレームの改ざんもできない。
Base64URL は符号化であって暗号化ではなく,誰でも復号して読め,書き換えられる。完全性は署名が担保するもので,符号化と暗号化を混同している。
エRS256 の署名は RSA 秘密鍵がなければ作れないので,公開鍵が公開されていても,ヘッダの alg を書き換えるだけでは偽造したトークンは受理されない。
署名の生成に秘密鍵が必要なのは RS256 で検証される場合に限られる。この実装は alg に従ってアルゴリズムを選ぶので,none や HS256 に変えられると秘密鍵なしで検証を通過され得る。
検証用の出典出典照合済み
RFC 8725 JSON Web Token Best Current Practices / RFC 7519 JSON Web Token (JWT) / CWE-347 Improper Verification of Cryptographic Signature照合の根拠(4 件)
- イ(正解): alg を RS256 から HS256 に変えられると,RSA 公開鍵を HMAC の共有鍵として検証する実装がある。公開鍵は公開されているので攻撃者は同じ鍵で HMAC を計算できる。エ(誤り): alg の書換えで秘密鍵なしに検証を通過され得る
An "RS256" (RSA, 2048 bit) parameter value can be changed into "HS256" (HMAC, SHA-256), and some libraries would try to validate the signature using HMAC-SHA256 and using the RSA public key as the HMAC shared secret (see [McLean] and [CVE-2015-9235]).
RFC 8725 · Section 2.1(新しいタブで開きます) - ア(誤り): alg を none に変えられると,その値を信頼して署名を確かめずに受理する実装がある
The algorithm can be changed to "none" by an attacker, and some libraries would trust this value and "validate" the JWT without checking any signature.
RFC 8725 · Section 2.1(新しいタブで開きます) - イ(正解): 対策として鍵ごとに 1 つのアルゴリズムに固定し,検証時に確かめる
Moreover, each key MUST be used with exactly one algorithm, and this MUST be checked when the cryptographic operation is performed.
RFC 8725 · Section 3.1(新しいタブで開きます) - ウ(誤り): 暗号化しない JWT の内容は保護されず,秘匿には JWT の暗号化か TLS が要る。Base64URL 符号化は秘匿の手段ではない
One way to achieve this is to use an encrypted JWT and authenticate the recipient. Another way is to ensure that JWTs containing unencrypted privacy-sensitive information are only transmitted using protocols utilizing encryption that support endpoint authentication, such as Transport Layer Security (TLS).
RFC 7519 · Section 12(新しいタブで開きます)
Base64URL が文字集合を変えるだけの符号化であることは RFC 7515 Section 2(Base64url Encoding の定義)でも確かめた。