didrod205/will-it-redos
GitHub: didrod205/will-it-redos
扫描 JS/TS 代码库,检测会引发指数级或多项式回溯的危险正则表达式,并生成可实际验证的恶意输入字符串。
Stars: 1 | Forks: 0
# 会导致 ReDoS 吗?
### 找出代码中只需一个 HTTP 请求就能让服务器卡死的 regex —— 以及导致该问题的准确字符串。
[](https://www.npmjs.com/package/will-it-redos)
[](https://github.com/didrod205/will-it-redos/actions/workflows/ci.yml)
[](https://www.npmjs.com/package/will-it-redos)
[](./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发现, 安全检测, 拒绝服务攻击, 数据可视化, 自动化攻击, 配置错误