DoS 是 denial of service 的缩写,意思是服务不可用。DoS 攻击是从攻击的目的或意图这个角度来命名的,意思是为了让对方的服务不可用而发起的攻击。
一个很出名的词是 DDoS,它是 distributed denial of service 的缩写,意思是分布式的 DoS 攻击。
这里说的是 ReDoS,意思是基于 Regex 发起的攻击。为了方便理解,我让 ChatGPT 给出一个 ReDoS 攻击的例子,当然我有所改动:
import timespand from "time-span";
const end = timespand();
const input = "a".repeat(30) + "b";
const regex = /^(a+)+$/;
const match = regex.test(input);
console.log(match); //结果是 false
console.log(end()); //在我的 Apple M1 Pro 电脑上耗时 35s
上面这段代码,在我的 Apple M1 Pro 电脑上执行,耗时长达 35 秒。
假设你的应用有一个输入框,你的后端使用 /^(a+)+$/
对用户的输入进行正则处理,然后攻击者输入了 aaa...(一共30个a)...aaab
,那攻击者就会让你的服务卡住 35 秒。
如果攻击者输入了更多的 a,比如 10000 个,那你的后端可能会卡住很长很长时间,导致无法向正常用户提供服务,于是攻击者达成了他的 ReDoS 攻击。
所以作为开发者,要注意小心写书你的正则法则,像例子中的 nested repetition operators 是需要避免的,例如可以改为 /^(a{1,10})+$/
,确保了 a 的数量不能超过 10 个。
另一种应对方法是,当发现正则处理耗时太久时,就直接让它超时:sindresorhus/super-regex
一种更好的做法是使用 uhop/node-re2 创建正则对象,不使用 Node.js 内置的正则引擎。
把例子中的 const regex = /^(a+)+$/
改为以下代码就没问题了:
import RE2 from "re2";
const regex = new RE2(/^(a+)+$/);
类似的库还有 re2js。