didrod205/will-it-redos

GitHub: didrod205/will-it-redos

扫描 JS/TS 代码库,检测会引发指数级或多项式回溯的危险正则表达式,并生成可实际验证的恶意输入字符串。

Stars: 1 | Forks: 0

# 会导致 ReDoS 吗? ### 找出代码中只需一个 HTTP 请求就能让服务器卡死的 regex —— 以及导致该问题的准确字符串。 [![npm version](https://img.shields.io/npm/v/will-it-redos.svg?color=success)](https://www.npmjs.com/package/will-it-redos) [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/88b4f32321144613.svg)](https://github.com/didrod205/will-it-redos/actions/workflows/ci.yml) [![types](https://img.shields.io/npm/types/will-it-redos.svg)](https://www.npmjs.com/package/will-it-redos) [![license](https://img.shields.io/npm/l/will-it-redos.svg)](./LICENSE) ``` npx will-it-redos scan . ```
2019 年 7 月 2 日,仅仅一个 regex —— `.*.*=.*` —— 就导致 **Cloudflare 的整个全球 网络瘫痪了** 27 分钟。2016 年 Stack Overflow 因为同样的原因宕机。这个 bug 被称为 **ReDoS**(正则表达式拒绝服务):一种在接收到特定输入时,会让引擎尝试*指数级*数量匹配方式的模式 —— 只需一个简短的字符串,就能让一个 CPU 核心永远处于 100% 满载状态。 它隐藏在看起来完全正常的 regex 中: ``` const TRIM = /^(\s+)+$/; // 💥 exponential const VALID = /^(\w+\s?)*$/; // 💥 exponential const EMAIL = /^([a-zA-Z0-9]+)*@.../ // 💥 exponential ``` **`will-it-redos` 能找出它们 —— 并通过提供导致卡死的输入字符串来证明这一点。** ``` $ npx will-it-redos check '(a+)+$' /(a+)+$/ WILL ReDoS exponential backtracking Nested quantifier (a `(x+)+` shape). On a long run of the inner character followed by a non-match, the engine tries exponentially many ways to split it. The input that hangs it: "a".repeat(50000) + "!" Proof (live, on this machine): 19 chars 2.9 ms ▪ 21 chars 11.8 ms ▪ 23 chars 44.1 ms ▪ 25 chars 173.7 ms ▪ 27 chars 725.5 ms ████████ ☠ 27 characters froze this regex for 726 ms. Imagine that as a request parameter. ``` 这绝不是 lint 规则的瞎猜。它**解析了模式,发现了其中的歧义,构建了恶意字符串,并精确计算了灾难发生的时间** —— 就在眼前。 ## 扫描你的整个代码库 ``` $ npx will-it-redos scan src --prove EXPONENTIAL src/validate.js:5:21 /^(\s+)+$/ Nested quantifier — on a long inner run + a non-match, the engine explodes. evil input: " ".repeat(50000) + "!" proven: 27 chars hung this regex for 337 ms (exponential) POLYNOMIAL src/parse.js:16:16 /.*.*=.*/ Two adjacent unbounded quantifiers over overlapping characters — quadratic. evil input: "a".repeat(50000) + "\n" 2 risky regexes · 1 exponential · 1 polynomial · 14 safe · 0 skipped · 16 total ``` 它会读取你的 `.js`/`.ts`(以及 jsx/tsx/mjs/cjs)文件中的 regex **字面量** *以及* `new RegExp("…")` 字符串,区分 regex 和除法操作,并且**只要有可能,就绝不误报安全的 regex** —— 误报是导致安全工具被忽视的罪魁祸首。 ## 安装 ``` npx will-it-redos scan . # no install npm i -g will-it-redos # keep it; the bin is also `redos` ``` Node ≥ 18。核心代码零依赖(CLI 仅添加了 `cac` + `picocolors`)。**无需 API key、无需联网、不收集任何 telemetry** —— 它完全在你的本地机器上运行,因为从本质上讲,它只是非常快速地对字符串执行 regex 匹配。 ## 将其作为 CI 门禁使用 `scan` 在发现问题时会以非零状态退出,因此只需一行代码就能将灾难性的 regex 永远拒于代码库之外: ``` # .github/workflows/ci.yml - run: npx will-it-redos scan src ``` ``` // package.json { "scripts": { "lint:redos": "will-it-redos scan src --min-severity polynomial" } } ``` Exit `0` = 干净 · `1` = 发现了易受攻击的 regex · `2` = 使用错误。 ## 它能捕捉到什么 | 形态 | 示例 | 结论 | | ----- | ------- | ------- | | **嵌套量词** | `(a+)+`, `(a*)*`, `([a-z]+)*`, `(.*)*` | 指数级 | | **量词修饰的歧义分组** | `(\w+\s?)*`, `([^=]+)+=` | 指数级 | | **循环下重叠的分支** | `(a\|a)*`, `(\w\|\d)*`, `(.\|a)*` | 指数级 | | **相邻的贪婪量词** | `.*.*=.*`, `\s*\s*$`, `\d+\d+` | 多项式级 | 它对 JS regex 语法(字符集、分组、分支、量词、lookarounds、backrefs)进行建模,并深入分析**字符集重叠**和**空匹配能力** —— 这正是导致回溯爆炸的两个核心属性。任何它无法解析的内容都会被报告为*已跳过*,绝不瞎猜。 ## 坦诚面对局限性 ReDoS 检测在通用情况下是不可判定的,因此 `will-it-redos` 的目标是**在真实世界规则库上实现高召回率与近乎零的误报率**: - 它可能会**遗漏**某些冷门构造(如 `(.*a){200}` 这样的有界重复放大,或由 backreference 驱动的爆炸)。`--prove` 参数是最后的防线:如果它标记了某个问题,耗时的测量结果就能证明这是真实的。 - 它**不会**执行你的代码 —— 它只读取源代码文本并分析模式。 - `--prove` 的计时是有界且自我保护的(微步进,硬性上限),因此该工具自身永远不会卡死。 ## Library API 分析器是纯粹的且对浏览器安全的: ``` import { analyzePattern } from "will-it-redos"; const r = analyzePattern("(a+)+$"); r.status; // "exponential" r.findings[0].attack.build(50000); // the evil input, ready to fire ``` ## 路线图 - 🌐 **Web playground** —— 粘贴一个 regex,看着它崩溃(100% 客户端运行;引擎已能在浏览器中运行)。 - 有界重复放大(`(.*a){n}`)与 backreference 分析。 - 自动修复建议(atomic groups / 占有模式重写 / anchoring)。 - ESLint 插件以及用于 pre-commit 的 `--git-diff` 模式。 ## 💖 赞助 免费、基于 MIT 协议、业余时间打造。如果它在坑到你之前抓住了 regex: - ⭐ **给仓库点个 Star** —— 这样下一个人就能在事故发生前找到它。 - 🍋 **[通过 Lemon Squeezy 赞助](https://elab-studio.lemonsqueezy.com/checkout/buy/5d059b89-51d0-456b-b33a-ed56994f7010)** —— 一次性或长期赞助。 ## License [MIT](./LICENSE) © will-it-redos 贡献者
标签:GNU通用公共许可证, MITM代理, Node.js, URL发现, 安全检测, 拒绝服务攻击, 数据可视化, 自动化攻击, 配置错误