常识指南
柔彩主题三 · 更轻盈的阅读体验

Perl正则注入防范:别让一条规则毁了你的程序

发布时间:2026-01-08 20:10:30 阅读:225 次

写脚本处理文本时,正则表达式用起来特别顺手。但如果你在 ref="/tag/2034/" style="color:#8B0506;font-weight:bold;">Perl 里动态拼接正则,又没做防护,那可能已经埋下了安全隐患——这就是所谓的“正则注入”。

什么是正则注入?

想象你有个搜索功能,用户输入关键词,程序自动把它放进正则里去匹配日志文件。比如用户输了个 error.*500,你直接拼成 /$user_input/ 去匹配。这看着没问题,但如果他输入的是 (.*){1000}evil 这种恶意模式呢?

这种输入可能触发回溯灾难,让 CPU 直接拉满,服务卡死。更糟的是,有些场景下还能绕过过滤逻辑,把不该匹配的内容放过去。

一个真实的翻车现场

有次上线个日志分析工具,允许运维填自定义过滤规则。结果某天系统突然无响应,查下来是有人误用了 .*.*.*.* 这类嵌套通配符,导致单条正则执行了几分钟。虽然不是恶意攻击,但效果等同于拒绝服务。

怎么防?三条实用建议

1. 别让用户直接拼正则

最简单的办法就是不让他们碰正则语法。比如提供“包含”“以…开头”“精确匹配”这些选项,后台转成安全的模式。用户想搜 login,你就用 \Q$user\E 包一层:

my $safe_pattern = quotemeta($user_input);
if ($log_line =~ /$safe_pattern/) { ... }

quotemeta 会把所有元字符转义,不用担心 . 或 * 被滥用。

2. 限制执行时间和复杂度

Perl 本身不支持超时中断正则,但可以用 alarm 搞个兜底:

eval {
    local $SIG{ALRM} = sub { die 'timeout'; };
    alarm(3);
    if ($text =~ /$dangerous_regex/) {
        # 处理匹配
    }
    alarm(0);
};
if ($@ && $@ !~ /timeout/) { die $@; }

这样哪怕遇到恶性回溯,最多卡 3 秒就会退出。

3. 白名单过滤 + 长度控制

如果非得让用户写正则,那就加上限制。比如只允许字母、数字、点号和基本量词,禁止嵌套括号和贪婪匹配。再限制整个表达式不超过 100 个字符。

if (length($user_regex) > 100 || $user_regex =~ /[\{\[\^\$\|\(\*\+\?]/) {
    die '不允许的正则格式';
}

虽然不能防住所有情况,但能挡住大部分明显有问题的输入。

小改动,大不同

正则注入不像 SQL 注入那么出名,但危害一样不小。特别是在自动化运维、日志分析这类场景里,一条失控的正则能让整个系统瘫痪。花几分钟加个转义或超时机制,远比半夜被报警电话叫醒强。