jay-tank/jotwatch

GitHub: jay-tank/jotwatch

一个零配置的静态 JWT 安全扫描器,通过 CI 退出码在代码层面拦截 JWT 配置错误,防止攻击者伪造令牌。

Stars: 0 | Forks: 0

# jotwatch **在攻击者伪造 token 之前,静态捕获 JWT 配置错误。** 一个错误的标志就能将 JSON Web Token 认证变成一扇敞开的大门:如果接受 `"none"` 算法,任何人都可以发送带有 `"role":"admin"` 的未签名 token; 如果调用 `jwt.decode()` 而不是 `jwt.verify()`,你的应用所信任的声明 将受到攻击者的控制。这些错误经常被发布,它们绝不会在正常路径测试中失败, 而这正是 [RFC 8725 (JWT Best Current Practices)](https://www.rfc-editor.org/rfc/rfc8725) 和 [OWASP JWT Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html) 所警告的内容。 `jotwatch` 是一个零配置、与语言无关的闸门,它会扫描你的源代码,并通过 干净的 CI 退出代码标记出这些模式。 ``` $ jotwatch . ● 2 JWT blocker(s): src/auth.js:15 JWT verification accepts the "none" algorithm. ↳ The "none" alg means an unsigned token. An attacker can drop the signature and forge any claim (RFC 8725 §3.1). Pin an explicit allow-list of signing algorithms and never include "none". [JW001] src/auth.js:21 jwt.decode() reads claims without verifying the signature. ↳ In jsonwebtoken, decode() does NOT check the signature — its claims are attacker-controlled. Use jwt.verify(token, key, {algorithms:[...]}) ... [JW002] 2 blockers · 1 warning ``` 遇到 blocker 会返回退出代码 `1`,因此可以直接将其接入 pre-commit 或 CI。 ## 为什么它与众不同 大多数 JWT 工具都是用于*运行时*的攻击套件(如 jwt_tool、jwt-scanner),它们会猛烈攻击实时的 endpoint,或者是深埋在大型 SAST 平台中的 JWT 规则。`jotwatch` 则恰恰相反:它是一个独立、零依赖的静态闸门,只专注于一件事——JWT 安全——它能在几毫秒内在你的源代码上运行,无需服务器,无需配置,也无需语言插件。 ## 工作原理 `jotwatch` 逐行读取每个源文件,并匹配少量基于 RFC 8725 / OWASP 的不区分大小写的模式。它是一个启发式扫描器,而不是类型检查器:不执行任何代码,不进行任何网络调用,也没有任何需要配置的东西。它是一个单一的静态 Go 二进制文件。 唯一与语言相关的细节是:仅在 JavaScript/TypeScript 中,单纯的 `jwt.decode()` 会被标记,因为在 Node 的 `jsonwebtoken` 中,`decode()` 会跳过验证——而在 Python 的 PyJWT 中,`jwt.decode()` *正是*用于验证的调用。 ## 规则 | 规则 | 严重程度 | 标记内容 | 依据 | | :--- | :--- | :--- | :--- | | JW001 | blocker | 接受 `"none"` 算法(`"alg":"none"`、`algorithms:["none"]` 等) | RFC 8725 §3.1 | | JW002 | blocker | 禁用签名验证(`verify=false`、`verify_signature:false`、JS 中的 `jwt.decode()`) | RFC 8725 §2.2 | | JW003 | warning | 不强制检查过期时间(`verify_exp:false`、`ignoreExpiration:true`) | RFC 8725 §3.9 | | JW004 | warning | 传递给 JWT 调用的签名密钥是硬编码的字符串字面量 | OWASP JWT Cheat Sheet | 规则倾向于较低的误报率:JW004 仅在字符串字面量作为 key 参数直接传递给 `jwt.sign/encode/verify` 调用时触发,因此从环境中加载的 key 永远不会被标记。 ## 安装 ``` go install github.com/jay-tank/jotwatch@latest ``` 或者从源码构建:`go build -o jotwatch .` ## 用法 ``` jotwatch # scan the current directory jotwatch ./src # scan a path jotwatch --strict # treat warnings (JW003/JW004) as failures too jotwatch --json # machine-readable output ``` ### 在 CI 中 ``` - run: go run github.com/jay-tank/jotwatch@latest ./ --strict ``` 退出代码:`0` 表示干净 · `1` 表示存在 blocker(或在 `--strict` 下存在任何发现) · `2` 表示使用错误。 ## 抑制误报 `jotwatch` 是一个启发式闸门。要屏蔽某一行,请在其上添加 `jotwatch:ignore` 注释(`// jotwatch:ignore` 或 `# jotwatch:ignore`)。要跳过整个路径,请在 `.jotwatchignore` 文件中列出路径子字符串(每行一个,使用 `#` 进行注释)。 ## 范围 `jotwatch` 能够很好地回答一个聚焦的问题——*“这段代码是否接受不安全的 JWT?”*——它跨越各种语言,作为一个快速的静态闸门。它不能证明你的验证在其他方面是完美的(正确的受众、正确的签发者、密钥轮换);它捕获的是少数几个最直接让攻击者能够伪造 token 的错误。 ## 许可证 MIT © Jay Tank
标签:DevSecOps, EVTX分析, Go, JWT, Ruby工具, URL发现, 上游代理, 动态分析, 安全检测, 日志审计, 错误基检测, 静态代码分析