通过 string.pattern() 进行 ReDoS,使用灾难性回溯正则表达式阻塞事件循环
作者: zhangjiashuo-cs创建于 2026年5月24日更新于 2026年7月12日
说明
Joi.string (.pattern (re)'直接使用regExp.test ()',没有安全包装。 当 schema 开发者通过(或在运行时接受)有嵌入式修饰(如"((a+)+)"+$")的regex时,验证甚至短攻击者控制的字符串会将事件回路阻断一秒到一分——经典的常规-Expression Deligial-Off-Service(ReDoS).
复制(joi 17.13.3)
Const Joi = 需要 ('joi' );
const schema = joi.string (. pattern (/(a+)+)+ $/;
const 输入 = 'a'.repeat (22) +'!'; // 23个字符
const t0 = 日期. now();
schema.validate(输入);
a. 控制台. log( “已消除” 、 Date. now( ) - t0, “ms” );
//已过期 / 5000ms( 屏蔽事件循环)每增加一个`a'大约是时间的两倍:
- 输入长度 * * * * 已过* * |-|-|-.
- 18 + ! + ~ 300 ms → + 18 + ! ~ 20 + !" ~ 1.2 s ~ |.
- 22 + ! + ~ 5 s + + | ~ 24 + ! ~ 20 s ~ ~ ~ ~ 24 + ! ~ ~ ~ 20 s ~ ~
- 28 + ! + 5 分钟 + 5 分钟
(a*)*美元'、(a*aa)美元'、`(aa?)*美元'等图案表现了同样的行为。
失败的属性
[JavaScript] 从“快速检查”中导入 fc; 从“joi”中导入Joi;
// 一个 schema 开发者从经过验证的部件中构成一个图案; 是否 / 由此产生的 regex 是 ReDoS- safe 在编译时并不明显. fc.sert(fc.property) (英语). fc.整数({min: 1, 最大: 30}), (n) {{{ const schema = joi.string (. pattern (/(a+)+)+ $/; const t0 = 日期. now(); schema.validate ("a". repeat(n) + "!"); s. 返回( Date.now () - t0) < 1000; // < 1 s 用于任何小输入 {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢? 页:1 // Shrinks 为 n=22
威胁模式
两种现实的攻击情景:
1. ** 公共监管-保密终点**: 一个API允许用户指定一个"名称模式","URL模式",或类似自定义验证 regex(joi-based JSON Schema admin工具,低码格式构建器). 一个恶意用户提供灾难性回溯模式;随后通过它的请求将服务器挂起.
2. **利用用户提供的regex** 构建的系统计划,利用用户输入(如:`Joi.string (.pattern (new RegExp (req.body.pattern))'):直接处理通过该处理器的每一项请求。
即使对于硬编码regex的策略,第三方的策略库,将用户输入到joi模式中,也会继承这个问题.
建议改正
将“regex.test(value)”呼叫中包含:
1. ** 同步超时** 通过`vm.run InNewContext({timeout:N})' (rough,但只为 N ms 屏蔽事件循环)。
2. ** 与Thompson-NFA后置发动机相匹配**的Joi模式(例如`re2'通过`re2'/`re2-WASM')。 默认为安全引擎;让用户选择进入本地的“RegExp”并有明确的警告。
3. **至少**:利用静态分析(如`安全记录 ' 或`再检查 ' ),在登记时间 " pattern(re) " 检测灾难性回溯模式,并拒绝或警告。
" Yup " 、 " Zod " 和 " jav " 都在记录ReDoS的关切方面趋于一致;其中许多人提出了`format: re2 ' 选项。 Joi没有文件
环境
- 乔伊:17.13.3
- 节点:20+内容来源: hapijs/joi