Perl正则表达式作为用户搜索输入(卫生处理)

时间:2019-05-01 09:20:32

标签: regex perl

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

重要!这部分代码是在用户监禁模式下运行的,这意味着可能只能自我开发。除此之外,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. 另一方面,但熟悉的问题是,当进一步运行替换时,是否也可以注入/利用 replace 部分,以及 在匹配文件的内容中安全地运行替换

示例:

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

$text_to_replace_with可以直接从用户传递过来,因此可以避免作为安全隐患吗?

1 个答案:

答案 0 :(得分:3)

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

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

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

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

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

      

    RE2的设计和实现的明确目标是能够无风险地处理不受信任用户的正则表达式。

    您可以通过这样做use it in your code

    {
        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()。同样,您不能以用户身份攻击它。您必须对其进行编码。)