Сообщение об ошибке
Error(InvalidSignature)
Также выводится как
- called `Result::unwrap()` on an `Err` value: Error(InvalidSignature)
- InvalidSignature
`{:?}` выводит `Error(InvalidSignature)`, а `{}` — `InvalidSignature`; `.unwrap()` паникует с сообщением «called `Result::unwrap()` on an `Err` value: Error(InvalidSignature)».
jsonwebtoken (Rust crate) — ErrorKind::InvalidSignature from decode()
Что это означает
Крейт `jsonwebtoken` разобрал токен, принял его алгоритм, но подпись не прошла проверку с переданным `DecodingKey`. `Error(InvalidSignature)` — форма `Debug`, которую вы видите в журналах и при панике `unwrap()`; форма `Display` — просто `InvalidSignature`. Крейт не различает «неверный ключ» и «изменённый токен»: в обоих случаях подпись неверна для этого ключа.
Почему это происходит
DecodingKey не принадлежит подписанту
частоКлюч из другого окружения, жёстко прописанный в коде ключ после ротации у издателя или выбор JWK по позиции, а не по `kid`.
Подпись ECDSA в токене закодирована в DER
иногдаТокен, собранный вручную с подписью от KMS или OpenSSL, содержит DER (~71 байт) вместо 64-байтного r‖s, которого требует ES256; такой токен никогда не пройдёт проверку.
Различаются байты секрета HS256
иногда`DecodingKey::from_secret(b"...")` на одной стороне и `from_base64_secret("...")` на другой дают из одной и той же строки конфигурации разные ключи.
Как исправить
- 1.
Обрабатывайте вид ошибки явно
Отвечайте на `ErrorKind::InvalidSignature` кодом 401 и не смешивайте эту ошибку с истечением срока действия, чтобы клиенты не повторяли запросы с токеном, который никогда не пройдёт проверку.
rust use jsonwebtoken::errors::ErrorKind; match decode::<Claims>(&token, &key, &validation) { Ok(data) => Ok(data.claims), Err(e) => match e.kind() { ErrorKind::InvalidSignature => Err(AuthError::Unauthorized), // wrong key or tampered token ErrorKind::ExpiredSignature => Err(AuthError::Expired), _ => Err(AuthError::BadToken), }, } - 2.
Выбирайте ключ по kid из JWKS издателя
`JwkSet::find` и `DecodingKey::from_jwk` выбирают ровно тот ключ, который издатель указал в заголовке.
rust use jsonwebtoken::{decode_header, jwk::JwkSet, DecodingKey}; let header = decode_header(&token)?; let kid = header.kid.ok_or(AuthError::BadToken)?; let jwk = jwks.find(&kid).ok_or(AuthError::UnknownKey)?; // jwks: JwkSet fetched from the issuer let key = DecodingKey::from_jwk(jwk)?;