Perl通过正则表达式污染

MvG*_*MvG 6 regex security perl taint

精简版

在下面的代码中,$1被污染了,我不明白为什么.

长版

我正在使用perl v5.14.2 启用了污点检查模式的系统上运行Foswiki-T.调试该设置的问题,我设法构建以下SSCCE.(请注意,我编辑了这篇文章,第一个版本更长,更复杂,评论仍然参考.)

#!/usr/bin/perl -T
use strict;
use warnings;
use locale;
use Scalar::Util qw(tainted);
my $var = "foo.bar_baz";
$var =~ m/^(.*)[._](.*?)$/;
print(tainted($1) ? "tainted\n" : "untainted\n");
Run Code Online (Sandbox Code Playgroud)

尽管输入字符串$var未被污染且正则表达式已修复,但生成的捕获组$1仍然受到污染.我觉得很奇怪.

perlsec手册有这样说的污点和正则表达式:

通过将它们用作散列中的键,可能无法使用值; 否则绕过污点机制的唯一方法是从正则表达式匹配引用子模式.Perl假定如果你使用$1,$2等等引用一个子字符串,你就知道在编写模式时你在做什么.

我想,即使输入被污染,输出仍然没有污染.要观察来自无污染输入的反向,污染输出,感觉就像perl中的一个奇怪的错误.但是,如果有人读取更多的perlsec,它也会指向用户在perllocale的SECURITY部分.我们读到:

当使用locale生效时,Perl使用污点机制(参见perlsec)来标记变为依赖于语言环境的字符串结果,因此可能不值得信任.以下是可能受区域设置影响的运算符和函数的污点行为的摘要:

  • 比较运算符(lt,le,ge,gtcmp)[...]

  • 情况下映射插值(与\l,\L,\u\U)[...]

  • 匹配运算符(m//):

    标量真/假结果永远不会被污染.

    $1 如果使用locale(但不是use locale ':not_characters')有效,则子模式作为列表上下文结果或作为等传递,并且子模式正则表达式包含\w(以匹配字母数字字符),\W (非字母数字字符),\s(空格)字符),或\S (非空白字符).匹配的图案可变的,$&,$` (预匹配), $'(后匹配),和$+(最近匹配)也如用语言环境是在效果和正则表达式包含污点 \w,\W,\s,或\S.

  • 替代经营者(s///)[...]

        [⋮]

这看起来应该是一个详尽的清单.而且我看不出它如何能适用于:我的正则表达式是不使用任何的\w,\W,\s或者\S,因此它不应该依赖于语言环境.

有人能解释为什么这段代码会污染变量$1吗?

MvG*_*MvG 1

目前问题中引用的文档与 perl 5.18.1 的实际实现之间存在差异。问题是字符类。文档中提到了\\w, \\s, \\W, ,\\S听起来像是一个详尽的列表,而实现几乎对[\xe2\x80\xa6].

\n\n

正确的解决方案可能介于两者之间:像[[:word:]]应该污染的字符类,因为它取决于语言环境。我的固定清单不应该。字符范围[a-z]取决于排序规则,因此我个人认为它们也应该受到污染。\\d取决于语言环境对数字的看法,因此即使它既不是迄今为止提到的转义序列之一,也不是括号内的类,它也应该受到污染。

\n\n

所以在我看来,文档和实现都需要修复。Perl 开发人员正在致力于此。有关进度信息,请查看我提交的Perl 错误报告

\n\n

对于固定的字符列表,一种可行的解决方法似乎是作为析取的公式,即(?:\\.|_)代替[._]。它比较冗长,但即使在当前(我认为有问题的)perl 版本中也应该可以工作。

\n