我們平時開發(fā)時,會經(jīng)常使用到正則表達(dá)式進(jìn)行對數(shù)據(jù)檢驗(yàn),因?yàn)檫@樣很方便快捷。但是與此同時,卻悄悄地隱含了一些安全問題。下面我們就說一說ReDos,即正則表達(dá)式拒絕服務(wù)。此安全問題,常常是出現(xiàn)在web api請求檢驗(yàn)時,開發(fā)者為貪圖方便快捷而使用正則表達(dá)式對用戶請求的數(shù)據(jù)進(jìn)行簡單校驗(yàn)。
以下以Nodejs為案例,如下面代碼:
let regx = /^([a-z0-9A-Z]+[-|_|\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\.)+[a-zA-Z]{2,}$/; //校驗(yàn)Email的正則
let str = "nnnnnnnnnardy"; //長度為13的字符串
console.time("redos");
regx.test(str);
console.timeEnd("redos");
我的電腦是windows 10 ,臺式機(jī),8G 內(nèi)存,4核心,測得的平均耗時為0.245ms;
接下來,我們把要檢驗(yàn)的字符串長度加大:
let str = "nnnnnnnnnnnnnnnnardy"; //長度為20的字符串
此時測試的平均耗時為5ms;我們繼續(xù)把字符串長度增大:
let str = "nnnnnnnnnnnnnnnnnnnnnnnnnnardy"; //長度為30的字符串
此時測試的平均耗時為5s;我們繼續(xù)把字符串長度增大:
let str = "nnnnnnnnnnnnnnnnnnnnnnnnnnnardy"; //長度為31的字符串
Oh My God!此時測試的最高耗時居然達(dá)到了10s;我還試了35位長度的字符串,反正我等了2分鐘沒等到結(jié)果返回。
試想,如果我們的web接口,也加入了類似的正則校驗(yàn),那僅僅是因?yàn)橛脩舻腅mai的名稱長了點(diǎn),就足以影響到服務(wù)器的請求接收,這對項(xiàng)目來說是一個安全問題了。
為什么會出現(xiàn)ReDos??
原因是:大多數(shù)正則表達(dá)式引擎的工作原理相似,都會首先對合適的字符串進(jìn)行嘗試多匹配,一次失敗了,會嘗試下一個可能的匹配,如果所有可嘗試匹配情況都失敗后,就會進(jìn)行回溯,看是否有其他方法來消化前一個字符,如果匹配路徑太深且發(fā)現(xiàn)最后不匹配,又或者有多種匹配路徑,則最后回溯的步驟可能會變得非常大,從而導(dǎo)致了災(zāi)難性的回溯結(jié)果。
建議
- 不要對用戶輸入的或不確定長度的數(shù)據(jù)進(jìn)行正則檢驗(yàn)
- 盡可能找到適合的替代方法
附注
因?yàn)楦鞣N開發(fā)語言都有正則表達(dá)式,且實(shí)現(xiàn)方式相似,所以,ReDos并非局限于Nodejs一種語言。