我尝试使用(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仍然是一个问题。
答案 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及更低版本中完成状态机快得多的主要原因之一。