jose (JavaScript)JWT 库
错误信息
"alg" (Algorithm) Header Parameter value not allowed
jose (JavaScript) — JOSEAlgNotAllowed, code ERR_JOSE_ALG_NOT_ALLOWED
含义
令牌的 alg 头部指定的算法不在你传给 jwtVerify 的算法允许列表中。jose 在执行任何密码学运算之前就拒绝了它。这道关卡是有意设置的:alg 头部是攻击者可以控制的输入,必须由验证方而不是令牌来选择算法。
原因
允许列表与颁发者不同步
常见颁发者已从 RS256 切换到 ES256(或新增了一个使用不同算法的签名密钥),而验证方仍固定使用旧的算法族。在允许列表和密钥一起更新之前,所有新令牌都会验证失败——而且失败恰好从颁发者上线变更的那一分钟开始,这在日志中是很有用的取证线索。
允许列表中的算法名称写法不同
偶见比较方式是与 JOSE 名称精确匹配,并且区分大小写:配置文件中的“es256”“ECDSA”“P-256”或“SHA256withECDSA”永远无法匹配值为“ES256”的头部。(与头部不相符的密钥——例如用于 ES256 令牌的 P-384 密钥,或自身 alg 不同的 JWK——会以另一种方式失败:抛出描述该密钥的 TypeError。)
恶意或配置错误的客户端发送不同的 alg
罕见带有 alg: "none" 或意外 HS* 值的令牌,正是这项检查要拦截的对象。如果在日志中看到陌生的算法,应将其视为探测行为,而不是需要去兼容的 bug。
修复方法
- 1.
让允许列表、密钥与颁发者配置保持一致
先查看头部,再让三者保持一致。迁移期间可以暂时同时接受两种算法,并通过 JWKS 中的 kid 为每种算法分配各自的密钥。
js import { decodeProtectedHeader, jwtVerify } from "jose"; console.log(decodeProtectedHeader(token)); // { alg: "ES256", kid: "..." } await jwtVerify(token, jwks, { algorithms: ["ES256"] }); - 2.
尽量缩小允许列表
不要通过列出所有算法来“修复”这个错误。每种令牌类型只允许一个值,才是安全的最终状态;RFC 8725(JWT Best Current Practices)也是这样建议的。
js // good: exactly what your issuer signs with { algorithms: ["ES256"] } // bad: defeats the protection this error provides { algorithms: ["ES256", "RS256", "HS256", "PS256"] }