6

精简版

在下面的代码中,$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");

尽管输入字符串$var是未污染的并且正则表达式是固定的,但是生成的捕获组$1是被污染的。我觉得很奇怪。

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

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

我想即使输入被污染,输出仍然是未污染的。从未污染的输入观察相反的污染输出,感觉就像 perl 中的一个奇怪的错误。但是,如果阅读更多 perlsec,它也会将用户指向perllocale 的 SECURITY 部分。我们在那里读到:

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

  • 比较运算符(、、、和lt)[ … ]legegtcmp

  • 案例映射插值(使用、 或\l\L[ …]\u\U

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

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

    $1 如果使用区域设置(但不是)有效,并且子模式正则use locale ':not_characters'表达式包含\w(以匹配字母数字字符)、\W (非字母数字字符)、\s(空白字符)或\S (非空白字符)。如果使用区域设置有效并且正则表达式包含、、或,则匹配模式变量 、$&$` 匹配前)、$'(匹配后)和$+(最后匹配)也会受到污染 。\w\W\s\S

  • 替换运算符 ( s///) […]

        [⋮]

这看起来应该是一个详尽的列表。而且我看不出它如何应用:我的正则表达式没有使用 , 或 中的任何一个\w,所以\W它不应该依赖于语言环境。\s\S

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

4

1 回答 1

0

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

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

所以在我看来,文档和实现都需要修复。Perl 开发人员正在努力解决这个问题。有关进度信息,请查看我提交的 perl 错误报告。

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

于 2013-12-06T01:20:29.477 回答