如何在Perl中安全地验证不受信任的正则表达式?

时间:2013-12-03 17:27:34

标签: regex perl code-injection

This answer解释说要验证任意正则表达式,只需使用eval

while (<>) {
    eval "qr/$_/;"
    print $@ ? "Not a valid regex: $@\n" : "That regex looks valid\n";
}

然而,这让我觉得非常不安全,因为我希望这是显而易见的原因。有人可以输入,比如说:

  

富/; system('rm -rf /'); QR /

或他们可以设计的任何狡猾的计划。

防止此类事情的自然方法是逃避特殊字符,但如果我逃避了太多字符,我首先会严重限制正则表达式的用处。我相信,可以做出一个强有力的论据,即在用户正则表达式界面中,至少[]{}()/-,.*?^$!和空格字符应该被允许(可能是其他的),未转义,因为正则表达式具有最小的实用性。

是否可以在不限制正则表达式语言有用性的情况下保护自己不受正则表达式注入的影响?

2 个答案:

答案 0 :(得分:8)

解决方案只是改变

eval("qr/$_/")

eval("qr/\$_/")

这可以写得更清楚如下:

eval('qr/$_/')

但那还不是最优的。以下内容会好得多,因为它不涉及在运行时生成和编译Perl代码:

eval { qr/$_/ }

请注意,这两种解决方案都不能保护您免受拒绝服务攻击。编写一个比宇宙生命需要更长时间才能完成的模式非常容易。为了解决这种情况,您可以在已设置CPU ulimit的子项中执行正则表达式匹配。

答案 1 :(得分:1)

The Monastery进行了一些讨论。

TLDR:使用re :: engine :: RE2(-strict =&gt; 1);

确保将add(-strict =&gt; 1)添加到您的use语句或re :: engine :: RE2将重新回到perl的重新开始。

以下是来自junyer的quote,github项目的所有者。

RE2的设计和实现具有明确的目标,即能够在没有风险的情况下处理来自不受信任的用户的正则表达式。其主要保证之一是匹配时间在输入字符串的长度上是线性的。它的编写也考虑了生产问题:解析器,编译器和执行引擎通过在可配置的预算内工作来限制其内存使用 - 在耗尽时优雅地失败 - 并且它们通过避免递归来避免堆栈溢出。