PHP - 这是一种允许用户提供的正则表达式的安全方法

时间:2021-11-10 06:51:16

I would like to allow small user-defined regular expressions to be submitted for testing. However, there are many problems to consider from run-away server usage to more evil eval() usage.

我想允许提交小的用户定义的正则表达式进行测试。但是,从失控服务器使用到更恶劣的eval()使用,需要考虑许多问题。

To my knowledge I have handled all the problems I could think of in the following code. Are their any attack vectors I haven't thought of? (A rather naive question I know)

据我所知,我已经处理了以下代码中我能想到的所有问题。他们没有想到的任何攻击媒介吗? (我知道一个相当天真的问题)

function testRegex($regex)
{
    // null character allows a premature regex end and "/../e" injection
    if (strpos($regex, 0) !== false || ! trim($regex)) {
        return false;
    }

    $backtrack_limit = ini_set('pcre.backtrack_limit', 200);
    $recursion_limit = ini_set('pcre.recursion_limit', 20);

    $valid = @preg_match("~$regex~u", null) !== false;

    ini_set('pcre.backtrack_limit', $backtrack_limit);
    ini_set('pcre.recursion_limit', $recursion_limit);

    return $valid;
}


$regexes = array(
    "InvalidRegular)Expression",
    '',
    '\w+',
    '\/\w+/',
    'foo[bar]*',
    '\/\x00known/e' . chr(0x00) . chr(0),
    'known~e' . chr(0),
    'known~e' . chr(0x00),
    '[a-z]+',
    '\p{Lu}+',
);


foreach($regexes as $regex) {
    var_dump($regex, testRegex($regex));
}

If you want to see an example of a null-byte injection:

如果要查看空字节注入的示例:

$user_regex = '.+~e' . chr(0);
$user_match = 'system("whoami")';

var_dump(preg_replace("~$user_regex~u", $user_match, 'foo'));

2 个解决方案

#1


8  

Obviously, the only way to test whether a string is a valid regular expression is by compiling it (which is done when you call any of the matching functions), so what you're doing makes a lot of sense.

显然,测试字符串是否是有效正则表达式的唯一方法是编译它(在调用任何匹配函数时完成),所以你所做的事情很有意义。

The null-byte protection you have added is actually not necessary since 5.4, because there are already checks made in the leader, the middle and the ending. The latter in particular is a relatively recent commit (2011) to fix this bug.

自5.4以来,您添加的空字节保护实际上没有必要,因为已经在领导者,中间和结尾处进行了检查。特别是后者是一个相对较新的提交(2011)修复此错误。

Setting a lower backtrack and recursion limit is a good enough sandbox, perhaps you could check for a maximum length as well.

设置较低的回溯和递归限制是一个足够好的沙箱,也许您可​​以检查最大长度。

That said, this particular solution doesn't provide the ability to use modifiers such as /s, /i and /m; perhaps that's not your main concern at the moment, but rather food for thought :)

也就是说,这个特定的解决方案不能提供使用修饰符的能力,例如/ s,/ i和/ m;也许这不是你目前关注的主要问题,而是值得深思的:)

#2


1  

You could tell them to input something like {expression} and then use preg_replace(). That way, they only use what you let them.

您可以告诉他们输入类似{expression}的内容然后使用preg_replace()。这样,他们只使用你让他们的东西。

#1


8  

Obviously, the only way to test whether a string is a valid regular expression is by compiling it (which is done when you call any of the matching functions), so what you're doing makes a lot of sense.

显然,测试字符串是否是有效正则表达式的唯一方法是编译它(在调用任何匹配函数时完成),所以你所做的事情很有意义。

The null-byte protection you have added is actually not necessary since 5.4, because there are already checks made in the leader, the middle and the ending. The latter in particular is a relatively recent commit (2011) to fix this bug.

自5.4以来,您添加的空字节保护实际上没有必要,因为已经在领导者,中间和结尾处进行了检查。特别是后者是一个相对较新的提交(2011)修复此错误。

Setting a lower backtrack and recursion limit is a good enough sandbox, perhaps you could check for a maximum length as well.

设置较低的回溯和递归限制是一个足够好的沙箱,也许您可​​以检查最大长度。

That said, this particular solution doesn't provide the ability to use modifiers such as /s, /i and /m; perhaps that's not your main concern at the moment, but rather food for thought :)

也就是说,这个特定的解决方案不能提供使用修饰符的能力,例如/ s,/ i和/ m;也许这不是你目前关注的主要问题,而是值得深思的:)

#2


1  

You could tell them to input something like {expression} and then use preg_replace(). That way, they only use what you let them.

您可以告诉他们输入类似{expression}的内容然后使用preg_replace()。这样,他们只使用你让他们的东西。