模块 8 · 第 4 课(共 4)课程中的32/32~14 min
模块课程(4/4)
编写 ReDoS 安全模式
ReDoS(正则表达式拒绝服务)是一类攻击,其中 精心设计的输入会使正则表达式的匹配时间爆炸。 JS 引擎使用回溯:如果模式“不明确”,则在 不幸的是,它可以执行指数级的尝试。
经典的灾难模式
Code
Pattern: ^(a+)+$
Input: "aaaaaaaaaaaaaaaaaaaaab"为了匹配,引擎会尝试每个可能的“a”分区
两个 + 量词。对于 20 个“a”,即 2^20 = ~100 万次尝试。
30 个“a”,就是十亿。
其他危险的例子:
(a*)*b--“嵌套星”。(a|a)*-- 重叠的替代方案。(\w+)+@-- 带有外部量词的贪婪组。
如何发现危险
寻找这些结构:
- 量词中的量词:
(...+)+、(...*)*、(...{n,})+。 - 量词下的重叠替代项:
(a|ab)*、(\w|\d)+。 - 具有复杂替代方案的前瞻/后瞻重复。
防御性重写
Code
Dangerous: ^(\w+\s+)+$
Safe: ^(?:\w+\s+)*\w+$安全版本将基本情况与重复情况分开,删除 歧义。其他技术:
- 所有格量词 (
a++) -- JS 不支持,但在其他引擎中可用。 - 原子模式 (
(?>...)) -- 不在 JS 中。 - 在匹配之前限制输入的长度。
- 匹配超时(本课程的编辑器使用超时时间为 500 毫秒的工作人员)。
ReDoS 安全模式的建议
- 确保交替中的选项是互斥的(例如,不要使用
(a|a+))。 - 避免将嵌套量词应用于重叠表达式(例如
(\\s*)*)。 - 始终优先选择特定的否定字符类 (
[^\\n]*) 而不是通用通配符点 (.*)。
尝试一下
锻炼#regex.m8.l4.e1
尝试:0加载中...
识别重复字母的模式——但采用 ReDoS 安全的方式。使用单个字符类,而不是像 (a+)+ 这样的嵌套组。
正在加载编辑器...
显示提示
将危险的 (a+)+ 替换为简单的 a+。结果是一样的,但是安全。
3 次尝试后可用的解决方案
复习练习
锻炼#regex.m8.l4.e2
尝试:0加载中...
以 ReDoS 安全的方式识别由空格分隔的单词序列。使用结构“(?:word+spaces+)*word”而不是“(word+space+)+”。
正在加载编辑器...
显示提示
将捕获组 (\\w+\\s+)+ 替换为不相交版本 (?:\\w+\\s+)*\\w+。
3 次尝试后可用的解决方案
额外的挑战
锻炼#regex.m8.l4.e3
尝试:0加载中...
Make the vulnerable pattern `(\w+\s*)+:` which causes ReDoS safe, by removing the overlapping whitespace recursion.
正在加载编辑器...
显示提示
移动空格,使其不与组重复重叠: (?:\\w+\\s+)*\\w+:
3 次尝试后可用的解决方案