从命令行运行时,我们可以强制perl总是使用三个参数形式的open吗?

cuo*_*glm 8 security perl

perl从命令行运行单行具有安全隐患.

问题是选项-n/-p触发菱形运算符<>,它使用两个参数形式open,因此文件名包含特殊字符,perl不能按预期工作:

$ perl -pe '' 'uname|'
Linux
Run Code Online (Sandbox Code Playgroud)

或者当文件名开头时更危险>,比如>file.在这种情况下,文件将被截断.

要解决此问题,我们可以:

  • 使用CPAN中的ARGV :: readonly模块.
  • ARGV::readonly通过自己实现模块之类的功能:

perl -pe 'BEGIN{$_.="\0" for @ARGV} ...' ./*
Run Code Online (Sandbox Code Playgroud)
  • 使用-i选项,perl在处理之前检查文件是否存在.
  • 使用-T选项启用污染模式.

我认为所有解决方案都可以解决这个问题,但也会产生副作用.如果我们可以强制perl总是使用open它的论证形式,那将是一个更好的解决方案.

我想我们可以做到这一点,强制perl总是使用你的论证形式open

注意

这个问题仅适用于perl从命令行运行一个内联的情况,因为(当然)我们总是可以open在Perl脚本中使用三个参数形式.

mob*_*mob 2

在我之前的回答中,我假设ARGV文件句柄魔法模拟了 2 参数 open,但实际上并没有通过 Perl 的内置open函数。所以我进一步研究了它,我想我想出了一个解决这个问题的实际解决方案。

Perl_nextargv中的函数doio.c是perl 围绕文件句柄执行I/O 的地方ARGV

在该函数的while循环内,有两种打开文件句柄的调用。当LIKELY(PL_inplace)为 true 时(即,当使用开关运行 perl 时-i),调用为do_open_raw. 当LIKELY(PL_inplace)为 false 时,调用为do_open6。后一个调用能够打开到外部命令的管道,这通常是 OP 不想要的。

因此,解决方案如下:在源文件中doio.c,将这些do_open6调用替换Perl_nextargvdo_open_raw并从源代码重建perl。对于 perl-5.22.0,原始代码如下所示

    if (LIKELY(!PL_inplace)) {
        if (nomagicopen
                ? do_open6(gv, "<", 1, NULL, &GvSV(gv), 1)
                : do_open6(gv, PL_oldname, oldlen, NULL, NULL, 0)
           ) {
            return IoIFP(GvIOp(gv));
        }
    }
Run Code Online (Sandbox Code Playgroud)

修改后的代码看起来像

    if (LIKELY(!PL_inplace)) {
        if (do_open_raw(gv, PL_oldname, oldlen, O_RDONLY, 0)) {
            return IoIFP(GvIOp(gv));
        }
    }
Run Code Online (Sandbox Code Playgroud)

nomagicopen当您使用perl 5.22.0 的<<>>语法时,该参数为 true 。我想我们可以将其设置true在函数的顶部,而不必更改其他任何内容,但上面的更改是旧版 perl 的通用解决方案)。

示例输出:

$ original-perl -pe '' a b c 'date|'
Can't open a: No such file or directory
Can't open b: No such file or directory.
Can't open c: No such file or directory.
Mon Sep 21 18:41:37 PDT 2015

$ modified-perl -pe '' a b c 'date|'
Can't open a: No such file or directory.
Can't open b: No such file or directory.
Can't open c: No such file or directory.
Can't open date|: No such file or directory.
Run Code Online (Sandbox Code Playgroud)