perl 的 s/../../e 有什么问题吗?

Is anything wrong with perl's s/../../e?

我正在寻找 Perl 相当于 python 的 re.sub,根据文档 repl 可以是字符串或可调用的.

我最终发现了 perl s// 函数的 e 修饰符,它允许我做如下事情:

my $n = 1;
sub repl {
    return $_[0] x $n ++;
}
my $hw = "hello world";
$hw =~ s/(l)/repl /eg;
say $hw;

并得到helllo worllld.

从安全的角度来看,我觉得它有点可疑。我假设 Mallory 控制了 $hw 字符串,我不相信这种方法的安全性,尽管我找不到任何可能的利用。

可以肯定的是,/ee 修饰符存在一些固有的错误:在 this thread 中搜索“vendetta”一词以获得线索。双 e 让我认为计算的表达式(在本例中为 repl )对应于隐式 eval('repl ').

是这样吗?

可能的问题示例

我们显然已经调用了 repl("foo lish"),但您可能想知道是否会评估 repl foo lish。这有点模棱两可。这不是问题,但我的问题是关于类似模式可能存在的陷阱。

它不会导致任何数据变成代码。它只是告诉 Perl 将 .pl 文件的一部分视为 Perl 代码。因此,它不会引入任何安全问题。

如果替换运算符是函数,则

s/pat/repl/     ⇒  substitute($_, qr/pat/, sub { qq/repl/ })
s/pat/repl()/e  ⇒  substitute($_, qr/pat/, sub { repl() })

这显然完全没问题。


进一步证明,用 /e 可以做的一切不用

也可以轻松完成。
s/pat/repl()/e

类似于

s/pat/${\( repl() )/

另一方面,

/ee 可能是一个安全问题。数据可以变成代码。

s/pat/repl/ee

类似于

s/pat/eval "repl"/e

替换模式插值出现问题[1]

$ echo 'print "0wn3d\n";' | perl -e'$_ = <>; s/(.*)//ee'
0wn3d

我从不使用 /ee,因为它掩盖了您使用 eval EXPR 的事实。


  1. 如果替换表达式不插入,则没有理由使用 /ee