Сообщение об ошибке
Provided key is too short
Также выводится как
- DomainException: Provided key is too short
Исключение выбрасывается и в `JWT::encode`, и в `JWT::decode`. php-jwt 6.x и более ранние версии принимали короткие ключи, поэтому ошибка обычно появляется сразу после обновления до 7.x.
firebase/php-jwt 7.x (PHP) — DomainException from JWT::encode / JWT::decode
Что это означает
php-jwt 7 проверяет размеры ключей перед подписью или проверкой: в секрете HMAC должно быть не меньше бит, чем в хеше (32 байта для HS256, 48 для HS384, 64 для HS512), ключ RSA должен иметь длину не менее 2048 бит, а ключ EC — не меньше размера, который подразумевает его алгоритм. Более короткий ключ отвергается, потому что защищённые им токены можно подделать: короткие секреты HMAC поддаются офлайн-перебору, а RSA с ключом 1024 бит не дотягивает до нынешних минимальных требований.
Почему это происходит
Короткий секрет HMAC, придуманный человеком
частоЗначения вроде `secret`, `change-me-please` или названия приложения намного короче 32 байт, и их к тому же часто можно угадать.
Обновление php-jwt с 6.x до 7.x
частоВ версии 7 появились проверки минимального размера ключа. Код и секреты, которые годами работали, отказывают на первом же запросе после `composer update`.
Ключ RSA длиной 1024 бит
иногдаСтарые ключи длиной 1024 бит (или скопированные из примеров) отвергаются для RS256/RS384/RS512.
Как исправить
- 1.
Сгенерируйте новый случайный секрет
Используйте `random_bytes` или `openssl rand` и храните секрет в хранилище секретов. После его смены существующие токены станут недействительными, поэтому при необходимости запланируйте короткий период, когда действуют оба секрета.
bash # HS256 needs >= 32 bytes, HS512 >= 64; generate and store as base64 php -r 'echo base64_encode(random_bytes(64)), PHP_EOL;' - 2.
Храните секрет в base64, а используйте декодированные байты
Проверяйте длину один раз при запуске, чтобы слабый секрет срывал развёртывание, а не первый запрос.
php $secret = base64_decode(getenv('JWT_SECRET_B64'), true); if ($secret === false || strlen($secret) < 32) { throw new RuntimeException('JWT_SECRET_B64 must decode to at least 32 bytes'); } $token = JWT::encode($claims, $secret, 'HS256'); $decoded = JWT::decode($token, new Key($secret, 'HS256')); - 3.
Замените короткие ключи RSA
Сгенерируйте ключ RSA длиной 2048 бит или больше (или перейдите на ES256 с ключом P-256) и опубликуйте новый открытый ключ до того, как начнёте подписывать новым ключом.
bash openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:3072 -out rs256-private.pem