Java ReDos容易受到攻击吗?

时间:2018-10-29 15:31:45

标签: java regex security java-11

我尝试使用(a+)+ regexp和aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!(带有大量a)(使用jshell)重新创建regular expression denial of service attack

Pattern.compile("(a+)+")
    .matcher("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!")
    .matches()

但是,每次我尝试都可以很快完成。 Java中的regexp实现与其他实现不同吗?还是链接的维基百科页面错误?

(顺便说一句。如果相关,我正在使用Java 11)

编辑:看起来它与Java版本相关,当我在Java 8上尝试过时,它挂起了,但是在Java 9和11中,它可以立即工作。这些版本之间的哪些变化可能会影响这一点? Java中所有正则表达式现在安全吗?

是否有特定的Java JEP更改了regexp实现?我想知道哪种正则表达式对于较新的Java仍然是一个问题。

2 个答案:

答案 0 :(得分:2)

根据文章RSPEC-2631,ReDoS问题已在Java 9及更高版本中处理:

像OpenJDK 9+这样的Java运行时通过在正则表达式评估的实现中提供其他保护来缓解此问题。在那些运行时中,上面的示例不容易受到攻击。

答案 1 :(得分:1)

我当前正在运行Java 8,并且以下代码挂起:

Pattern.compile("(a|aa)+")
       .matcher("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab")
       .matches()

看到您使用Java 11的方式(并且已经用Java 9/10对其进行了测试),并且花了少量时间才能完成,显然在这些版本之间进行了更改。

通过查看Java 11中的Matcher的源代码,我们发现Java 8中不存在以下附加内容:

/**
 * Storage used by top greedy Loop node to store a specific hash set to
 * keep the beginning index of the failed repetition match. The nodes
 * themselves are stateless, so they rely on this field to hold state
 * during a match.
 */
IntHashSet[] localsPos;

这种本地存储以及添加的大量其他代码,似乎是Java 9+中正则表达式的状态机比Java 8及更低版本中完成状态机快得多的主要原因之一。