エラーメッセージ
JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
別の表記
- io.jsonwebtoken.security.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
JJWT (Java) — io.jsonwebtoken.security.SignatureException from JwtParser.parseSignedClaims
このエラーの意味
JJWT は、設定された鍵を使って、トークンのヘッダーとペイロードに対する署名を再計算(HMAC)または検証(RSA、ECDSA、EdDSA)しましたが、トークンの署名セグメントと一致しませんでした。トークンの解析には問題がなく、アルゴリズムも鍵に適合しています。単に鍵とトークンが対応していないか、署名後にトークンが変更されています。
発生する理由
検証者が別の鍵を使っている
よくある別の環境の鍵、起動時に再生成される鍵ペア(そのまま本番環境に移されたデモでよくあるバグ)、古いシークレットを持ったままのサービスインスタンスが 1 つだけある場合などです。
同じ HMAC シークレットなのにバイト列が異なる
よくある一方は文字列の UTF-8 バイト列を使い、もう一方は先に base64 デコードしています(Spring のサンプルでは、base64 のシークレットを保存していることがよくあります)。設定上はシークレットが同じに見えても、生成される MAC は異なります。
kid を扱わない鍵のローテーション
ときどき発行者は新しい鍵で署名していますが、検証者はまだ古い鍵しか持っていません。`kid` をもとに鍵を探す鍵ロケーターがなければ、検証者はどの鍵が意図されているのかさえ判断できません。
トークンが変更された
ときどきヘッダーやペイロードのセグメントに対する変更は、空白文字や再エンコードも含めて、どんなものでも署名を無効にします。
修正方法
- 1.
鍵ロケーターで kid から鍵を解決する
JJWT 0.12 以降は `keyLocator` に対応しています。これはヘッダーを受け取り、適切な鍵を返します。ローテーションのたびに更新する JWKS と組み合わせてください。
java import io.jsonwebtoken.*; import java.security.Key; // Pick the verification key by the token's kid instead of a single static key. Locator<Key> keys = new LocatorAdapter<>() { @Override protected Key locate(JwsHeader header) { Key key = publicKeysByKid.get(header.getKeyId()); // refreshed from the issuer's JWKS if (key == null) throw new UnsupportedJwtException("unknown kid " + header.getKeyId()); return key; } }; Jws<Claims> jws = Jwts.parser().keyLocator(keys).requireIssuer("https://issuer.example.com/").build().parseSignedClaims(token); - 2.
HMAC 鍵のバイト列を揃える
設定されたシークレットがテキストなのか base64 なのかを決め、すべての側で同じ方法で鍵を導出してください。HMAC 計算ツールでは、両方の解釈での MAC を確認できます。
java // Both sides must derive the same key bytes. If the secret is stored base64-encoded, decode it. javax.crypto.SecretKey key = io.jsonwebtoken.security.Keys.hmacShaKeyFor( java.util.Base64.getDecoder().decode(System.getenv("JWT_SECRET_B64")));