firebase/php-jwt 7.x (PHP)PHP
错误信息
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 密钥的位数至少要等于哈希的位数(HS256 为 32 字节,HS384 为 48 字节,HS512 为 64 字节),RSA 密钥至少 2048 位,EC 密钥至少要达到其算法所要求的长度。更短的密钥会被拒绝,因为用它保护的令牌可以被伪造——过短的 HMAC 密钥经不起离线暴力破解,1024 位 RSA 则低于当前的最低要求。
原因
人为设定的过短 HMAC 密钥
常见`secret`、`change-me-please` 或应用名称这类值远不到 32 字节,而且往往还很容易被猜到。
将 php-jwt 从 6.x 升级到 7.x
常见版本 7 新增了最小密钥长度检查。用了多年都没有问题的代码和密钥,在执行 `composer update` 之后的第一个请求上就会失败。
1024 位的 RSA 密钥
偶见以 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 密钥
生成 2048 位或更长的 RSA 密钥——或者改用 ES256 和 P-256 密钥——先发布新的公钥,再用新密钥签名。
bash openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:3072 -out rs256-private.pem