正则表达式的灾难性回溯

最近项目上在做Fortify安全漏洞扫描。其中有一项漏洞扫描规则为:Denial of Service: Regular Expression。是由于正则表达式带来的DOS攻击。

      由于Fortify的扫描不够绝对的智能,因此,它将所有出现了正则表达式的代码,甚至String.split(regex)统统认为有正则表达式带来的DOS攻击风险。

       项目上有很多同事来询问该扫描规则的含义以及修改方式。我也上网查询并且做了一些测试。实际上,该漏洞扫描规则主要需要了解的,是关于正则表达式的灾难性回溯(catastrophic backtracking)。

       用如下一个简单的正则表达式来实际操作,会很简单明了的看到问题所在:

       正则表达式1:(a+)*

       正则表达式2:(a+)*s

       这两个正则表达式看上去很相似,第二个仅仅是要求最后必须匹配为s。

 

        我们再分别用两个不同的字符串来匹配。

        input1:aaaaaaaaas

        input2:aaaaaaaaab

        匹配结果应该是显而易见的:

        正则表达式1和input1匹配:true 

        正则表达式1和input2匹配:true

        正则表达式2和input1匹配:true

        正则表达式2和input2匹配:false

上述是匹配结果,是没有问题的。我们关注的,是操作时间。上述四种组合的匹配时间,基本上都在1ms的级别。

但是,我们把第四种匹配组合中,匹配字符串input2修改一下,input2为10个字符,我们将它修改成20个字符:

aaaaaaaaaaaaaaaaaaaab  运行时间变成113ms

继续将它修改成30个字符:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaab  在运行过程中,已经很清楚,出现灾难了,运行时间为111231ms

如果再加长,将会出现更夸张的时间增长。

      这就是正则表达式的灾难性回溯。在进行匹配的时候,匹配引擎在前面的a字符的时候,匹配成功,到达b的时候,匹配失败,就会进行回溯,而回溯的数量,和之前匹配的数量呈指数的增长趋势。

      而Foritfy的Denial of Service: Regular Expression漏洞规则,也正是怀疑正则表达式的来源以及匹配字符串的来源,当攻击者能够改写正则表达式,或者是我们代码中本来就有存在耗时可能性的正则表达式,而攻击者可以改写输入匹配字符串的时候,执行的耗时将是灾难性的。

       那么如何来防止这样的安全漏洞呢。其实正则表达式,我们在代码规范里面,通常都会推荐尽量少用,尽量简单。因为其效率,本身就不高,再则加上如果无法控制匹配字符串的来源,很容易造成问题。解决的方案首选当然是尽量少用正则表达式,尽量少用带有.*?等复杂表达式,如果一定要用,则必须控制匹配字符串的来源,进行来源验证或者是长度控制。

你可能感兴趣的:(正则表达式的灾难性回溯)