Perl通过正则表达式污染



短版本

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

长版本

我在启用了-T污染检查模式的perl v5.14.2系统上运行Foswiki。调试该设置的一个问题时,我设法构建了以下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) ? "taintedn" : "untaintedn");

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

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

通过将值用作哈希中的键,可以对其进行无损处理;否则绕过污点机制的唯一方法是引用正则表达式中的子模式匹配。Perl假定如果您使用$1$2等引用子字符串,您知道当你写图案的时候。

我可以想象,即使输入被污染,输出也不会被污染。从未污染的输入中观察相反的、受污染的输出,感觉就像perl中的一个奇怪的错误。但是,如果你阅读了更多的perlsec,它也会将用户指向perlscale的SECURITY部分。我们读到:

当使用区域设置生效时,Perl使用污染机制(请参阅perlsec)标记依赖于区域设置的字符串结果,以及其结果可能是不可信的。以下是可能受到以下影响的运算符和函数的污染行为区域设置:

  • 比较运算符(ltlegegtcmp)[…]

  • 案例映射插值(使用lLuU)[…]

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

    标量真/假结果从未受到污染。

    子模式,作为列表上下文结果或$1交付如果使用区域设置(但不是use locale ':not_characters')有效,并且子模式正则表达式包含w(用于匹配字母数字字符)和W(非字母数字字符)、s(空白字符)或S(非空白字符)。匹配模式变量$&$` (预赛)、$'(赛后)和$+(最后一场比赛)也是如果使用区域设置有效并且正则表达式包含wWsS

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

 nbsp nbsp nbsp nbsp;〔⋮〕

这看起来应该是一个详尽的列表。我不知道它是如何应用的:我的regex没有使用wWsS中的任何一个,所以它不应该依赖于语言环境。

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

问题中引用的文档与perl 5.18.1的实际实现之间目前存在差异。问题出在字符类上。文档中提到了wsWS,这听起来像是一个详尽的列表,而实现几乎影响了[…]的每一次使用。

正确的解决方案可能介于两者之间:像[[:word:]]这样的字符类应该有污点,因为这取决于区域设置。我的固定列表不应该。像[a-z]这样的字符范围取决于排序规则,所以在我个人看来,它们也应该有污点。d取决于区域设置对数字的看法,因此,即使它既不是迄今为止提到的转义序列之一,也不是带括号的类,它也应该是有污点的。

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

对于固定的字符列表,一个可行的解决方法似乎是将公式化为析取,即(?:.|_)而不是[._]。它更详细,但即使在当前(在我看来是bug)的perl版本中也应该可以使用。

相关内容

  • 没有找到相关文章

最新更新