Сообщение об ошибке
The specified key byte array is 96 bits which is not secure enough for any JWT HMAC-SHA algorithm.
Также выводится как
- io.jsonwebtoken.security.WeakKeyException: The specified key byte array is 96 bits which is not secure enough for any JWT HMAC-SHA algorithm.
- io.jsonwebtoken.security.SignatureException: Unable to compute HS512 signature. Cause: The signing key's size is 256 bits which is not secure enough for the HS512 algorithm.
- io.jsonwebtoken.security.WeakKeyException: The signing key's size is 256 bits which is not secure enough for the HS512 algorithm.
Число бит соответствует вашему ключу. `Keys.hmacShaKeyFor` сообщает «…not secure enough for any JWT HMAC-SHA algorithm». Если подписывать с явно заданным алгоритмом, для которого ключ слишком короткий, в сообщении будет назван этот алгоритм: JJWT 0.12+ оборачивает ошибку в «SignatureException: Unable to compute HS512 signature. Cause: The signing key's size is 256 bits…», а 0.11 выбрасывает её напрямую как `WeakKeyException`.
JJWT (Java) — io.jsonwebtoken.security.WeakKeyException from Keys.hmacShaKeyFor / signWith
Что это означает
JJWT отказывается создавать ключ HMAC, если в нём меньше бит, чем на выходе хеш-функции алгоритма: нужно не менее 256 бит (32 байта) для HS256, 384 для HS384 и 512 для HS512. В RFC 7518, § 3.2 это требование уровня MUST, потому что короткий общий секрет можно подобрать перебором офлайн по любому подписанному им токену. После этого кто угодно сможет выпускать действительные токены. Число в сообщении — размер переданных вами байтов.
Почему это происходит
Человекочитаемый секрет
частоЗначения вроде `secret`, `changeme` или короткая парольная фраза из учебника гораздо короче 32 байт. Их длина к тому же намекает, что они никогда не предназначались для продакшена.
Обновление с JJWT 0.9
частоJJWT 0.9 принимал короткие ключи, переданные строками. Версии 0.10+ требуют размеров ключей по RFC 7518, поэтому та же конфигурация после обновления перестаёт работать.
Ключа хватает для HS256, но не для HS512
иногдаКлюч длиной 32 байта подходит для HS256, но не для HS384/HS512. `signWith(key)` выбирает самый стойкий алгоритм, допустимый для этого ключа; если явно указать более стойкий, возникнет ошибка.
Как исправить
- 1.
Сгенерируйте случайный секрет нужного размера
Используйте криптографически случайное значение (64 байта подходят для всех вариантов HMAC) и храните его в менеджере секретов в кодировке base64.
bash # 64 random bytes, base64-encoded: enough for HS256, HS384 and HS512 openssl rand -base64 64 | tr -d '\n' - 2.
Декодируйте сохранённый секрет в байты
Создавайте ключ из декодированных байтов, а не из текста base64, чтобы все сервисы получали одинаковый ключ.
java import io.jsonwebtoken.io.Decoders; import io.jsonwebtoken.security.Keys; javax.crypto.SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(System.getenv("JWT_SECRET_B64"))); String token = io.jsonwebtoken.Jwts.builder().subject("user-42").signWith(key).compact();