Hooks

jwt hook:检测未固定算法的 JWT 验证

在命令行中扫描代码库里未固定算法的 JWT 验证,或评估单个调用。

jwt hook 会标记未固定算法的 JWT 验证,也就是验证方信任令牌自身 alg 头部的算法混淆漏洞,以及完全关闭了验证的情况。它能识别语言,按每个文件所用的 JWT 库来读取,也是 federation 专项 背后的确定性引擎,你也可以自己以 scan 或 check 模式运行它。

如何运行​

npx lagune read jwt # scans the whole project
npx lagune read jwt --dir src # scans a directory
npx lagune read jwt --file auth.ts # scans a single file

Unpinned JWT verification found 下的每一行都是一个验证调用:它没有设置 algorithms 白名单(在库需要时),或接受了不安全的白名单(none,或把非对称算法与 HMAC 混用),或干脆关闭了签名检查,因此会信任令牌自身的 alg。这是已确认的风险暴露,所以 hook 会以非零退出码退出。扫描结果干净时会输出 no unpinned JWT verification found。

如何解读判定结果​

判定结果含义
unpinned验证调用没有算法白名单(在需要的情况下)、使用了不安全的白名单,或关闭了验证。
safe验证调用固定了可靠的算法白名单,或者所用的库会隐式固定算法。
invalid代码片段中没有可识别的验证调用可供判定。

CLI 选项​

选项值说明
--pattern一个代码片段检查一个调用。可重复使用以检查多个,每行一个判定结果。
--lang一种语言使用 --pattern 时必填,取值为 javascript、python、go、java、kotlin、php、ruby、rust、csharp 之一。
--dir一个目录将扫描范围限定在某个目录。可重复使用,也可与 --file 组合。
--file一个文件将扫描范围限定在单个文件。可重复使用,也可与 --dir 组合。

不带任何选项时,它会扫描整个项目。--pattern 需要配合 --lang,且不能与 --dir 或 --file 组合使用。

支持的语言​

扫描会按文件扩展名识别以下库。由于有些库会隐式固定算法(没有显式列表也是安全的),"没有白名单 ⇒ unpinned"这条规则只适用于要求显式列表的库,因此配置正确的调用永远不会被标记。

语言库未设白名单时标记为 unpinned?始终标记
JavaScript / TypeScriptjsonwebtoken、jose是none、非对称算法与 HMAC 混用
PythonPyJWT、python-jose是(PyJWT 要求提供,python-jose 默认 algorithms=None)none、verify_signature: False
Gogolang-jwt是(未使用 WithValidMethods 时)none、ParseUnverified
Rubyruby-jwt是none、verify = false
Java / Kotlinjjwt、nimbus否(由密钥推导)none、unsigned/unsecured 解析器
PHPfirebase/php-jwt否(Key 自带 alg)none
Rustjsonwebtoken否(Validation 要求提供)none、insecure_disable_signature_validation
C#Microsoft.IdentityModel否(参数跨多行)none、RequireSignedTokens = false
提示

这个 hook 只判定算法是否固定:声明(claim)、密钥和流程方面的检查需要判断,仍由 federation 专项 负责。

常见问题

如果验证方从令牌头部读取算法,攻击者就能把 RS256 换成 HS256,并用公钥签名。在代码中固定一份可靠的算法白名单就能防止这种攻击,jwt hook 会标记没有设置白名单或白名单不安全的验证调用。