首页 > 解决方案 > Perl 正则表达式作为用户搜索输入(清理)

问题描述

我需要确保作为用户输入传递的regex不会意外终止并变成任意Perl 代码,但同时用于基本过滤目的。

重要的!这部分代码在用户监狱模式下运行,这意味着它可能只能被自我利用。除此之外,UI 只暴露给特定用户,并且可能针对有限数量的文件运行,因此潜在的 DoS 风险非常小。

为了达到我的目标,我创建了一个自定义函数,它首先将引用元全部,然后取消转义,只需要正则表达式来运行字符。

例子:

# Allow short range of special chars to be left unescaped
# to let regex work, while at the same time prevent possible
# command injection or premature regex termination
my $mask = $in{'mask'};
sub quotemeta_dangerous
{    
    my ($string) = @_;
    $string = quotemeta($string);
    $string =~ s/\\\\/\\/g;
    $string =~ s/\\\+/+/g;
    $string =~ s/\\\*/*/g;
    $string =~ s/\\\$/\$/g;
    $string =~ s/\\\^/\^/g;
    $string =~ s/\\\(/\(/g;
    $string =~ s/\\\)/\)/g;
    $string =~ s/\\\{/\{/g;
    $string =~ s/\\\}/\}/g;
    $string =~ s/\\\[/\[/g;
    $string =~ s/\\\]/\]/g;
    $string =~ s/\\\?/?/g;
    $string =~ s/\\\././g;
    $string =~ s/\\\-/-/g;
    return $string;
}

my $sanitized_mask = quotemeta_dangerous($mask);
if ($filename =~ /$sanitized_mask/) {
    # matched
}

问题:

  1. 考虑到提到的重要旁注,我上面的解决方案是否会帮助我安全地实现我的目标。我在这里看不到的潜在风险是什么?

  2. 作为一个熟悉的问题,当进一步运行替换时,替换部分是否也可以被注入/利用,如果是,如何安全地在匹配文件的内容中运行替换?

例子:

$file_contents =~ s/\Q$text_to_find\E/$text_to_replace_with/g;

$text_to_replace_with当从用户原样传递时,是否可以在此处避免安全风险?

标签: regexperl

解决方案


  1. 我不确定您所说的终止是什么意思。至于运行任意 Perl 代码,您不能通过用户输入来执行此操作(除非程序使用 egeval()或显式启用它use re 'eval')。如果您可以只从用户输入中注入 Perl 代码,您的函数将无法防范它:它允许通过例如(?{system+qq(rm -rf ~)})可运行形式(可运行,也就是说,如果它是代码的一部分,而不是输入数据)。

    您可以使用用户输入正则表达式执行的操作是创建 DoS:使其消耗大量 CPU 并挂起程序。您的功能不能防止这种情况。例如,尝试:

    'aaaaaaaaaa' =~ /(((\1?[a-z]*)*)*)*[b-z]/
    

    或者带有更长的a链。(可能有一些方法可以缩短此代码;我只是将随机位放在一起,看看它们是否快速完成匹配。)

    如果您想防止这种情况,请查看RE2

    RE2 的设计和实施具有明确的目标,即能够无风险地处理来自不受信任用户的正则表达式。

    您可以通过执行在代码中使用它

    {
        use re::engine::RE2 -strict => 1;
        # now regexes compiled in this scope will use the RE2 engine
        ...
    }
    
  2. 这很容易回答。这里没有危险;$text_to_replace_with被简单地视为一个字符串。

    (如果你想制造危险,你需要

    • /eeval(), 或
    • /ee,这是同一回事。

    从技术上讲,您不需要,但这仍然会在您的代码中/e留下非常明显的内容。eval()同样,您不能以用户身份攻击它;你必须把它编码进去。)


推荐阅读