【发布时间】:2012-12-01 12:13:30
【问题描述】:
我想允许两个主要的通配符 ? 和 * 过滤我的数据。
这是我现在的做法(正如我在许多网站上看到的那样):
public boolean contains(String data, String filter) {
if(data == null || data.isEmpty()) {
return false;
}
String regex = filter.replace(".", "[.]")
.replace("?", ".")
.replace("*", ".*");
return Pattern.matches(regex, data);
}
但我们不应该转义所有其他正则表达式特殊字符,如| 或( 等吗?而且,如果? 和* 前面有\,也许我们可以保留它们?例如,类似:
filter.replaceAll("([$|\\[\\]{}(),.+^-])", "\\\\$1") // 1. escape regex special chars, but ?, * and \
.replaceAll("([^\\\\]|^)\\?", "$1.") // 2. replace any ? that isn't preceded by a \ by .
.replaceAll("([^\\\\]|^)\\*", "$1.*") // 3. replace any * that isn't preceded by a \ by .*
.replaceAll("\\\\([^?*]|$)", "\\\\\\\\$1"); // 4. replace any \ that isn't followed by a ? or a * (possibly due to step 2 and 3) by \\
你怎么看?如果您同意,我是否缺少任何其他正则表达式特殊字符?
编辑#1(在考虑了 dan1111 和 m.buettner 的建议后):
// replace any even number of backslashes by a *
regex = regex.replaceAll("(?<!\\\\)(\\\\\\\\)+(?!\\\\)", "*");
// reduce redundant wildcards that aren't preceded by a \
regex = regex.replaceAll("(?<!\\\\)[?]*[*][*?]+", "*");
// escape regexps special chars, but \, ? and *
regex = regex.replaceAll("([|\\[\\]{}(),.^$+-])", "\\\\$1");
// replace ? that aren't preceded by a \ by .
regex = regex.replaceAll("(?<!\\\\)[?]", ".");
// replace * that aren't preceded by a \ by .*
regex = regex.replaceAll("(?<!\\\\)[*]", ".*");
这个呢?
编辑#2(在考虑了 dan1111 的建议后):
// replace any even number of backslashes by a *
regex = regex.replaceAll("(?<!\\\\)(\\\\\\\\)+(?!\\\\)", "*");
// reduce redundant wildcards that aren't preceded by a \
regex = regex.replaceAll("(?<!\\\\)[?]*[*][*?]+", "*");
// escape regexps special chars (if not already escaped by user), but \, ? and *
regex = regex.replaceAll("(?<!\\\\)([|\\[\\]{}(),.^$+-])", "\\\\$1");
// replace ? that aren't preceded by a \ by .
regex = regex.replaceAll("(?<!\\\\)[?]", ".");
// replace * that aren't preceded by a \ by .*
regex = regex.replaceAll("(?<!\\\\)[*]", ".*");
目标在望?
【问题讨论】:
-
如果这将出现在公共网站上,那么有人可能会使用它来攻击您的网站。他们可以创建一个永远不会匹配的正则表达式,并且构建为具有大量可能性,因此它将永远运行。然后他们可以用它来淹没你的服务器。
-
确实,dan1111 是正确的。如需进一步阅读,请查看en.wikipedia.org/wiki/ReDoS。
-
@dan1111 你在说哪段代码?如果您在谈论第一个,我同意您的看法,因为用户将能够在过滤器中编写自己的正则表达式。但是第二个的想法正是禁止任何正则表达式特殊字符,并且只允许
?和*通配符。 -
@sp00m,即使你只允许
.和*,这种攻击也是可能的。有关示例,请参见 m.buettner 的回答。基本上,多个相邻的.*模式会产生大量的匹配可能性,因为有很多方法可以将字符串分解为匹配组。.*.*可以通过五种不同的方式匹配abcd:('','abcd'), ('a','bcd')等等。随着更多.*的添加,这呈指数增长。正则表达式引擎将尝试所有可能性,直到找到匹配项。 -
@dan1111 你说得对,我试图在编辑我的问题时考虑到这一点。你现在怎么看?
标签: java regex string filter wildcard