如果你所使用的数据是tainted的,你想要Perl程序所做的大多数事情会产生出错信息。如果文件名或程序名是tainted的,那么运行程序,打开文件来写入,以及删除文件,这些操作都将被禁止进行。
这一节将演示如何在这种场合下,解除tainted状态。
考虑:
system("ls *.h");
Perl 在你的串中看到了 *,并决定调用shell,这样:
sh -c "ls *.h"
但是,的确有人可能用假的路径环境变量来运行你的程序,从而导致调用了错误的sh或ls。所以,对于PATH变量以及SHELL中可以用来修改其行为的其他变量,应该进行 untaint操作。
一般,运行其它程序时,你应采取三项步骤:
明确你的环境变量,使得运行的是实际程序。
关闭shell
对程序的参数进行untaint操作。
用如下的等简单方式清除你的环境变量:
|
delete @ENV{"IFS", "CDPATH", "ENV", "BASH_ENV"};
$ENV = "/bin:/usr/bin";
|
第一行删除掉可能会引起问题的环境变量,第二行给出一个确保安全的PATH。你可以添加其他的目录到PATH中,但务必确保它们同该处一样,是有确定值的。
关闭shell也要把握好分寸。Perl 在涉及到有关shell的操作,如 open(), system(), backticks,和exec() 调用时,有自己的规则,这些规则不太容易掌握。最好的规则是:避免使用backticks 和pipe open() 调用,而是使用system() 和exec() ,并传给它们参数表。
大多数人习惯于看到如下的写法:
system("someprogram arg1 arg2 arg3");
他们不知道还可这样写:
system("someprogram", "arg1", "arg2", "arg3");
这样的写法,可以精确地告诉Perl的各个参数是什么,Perl将不会调用shell。 exec() 也具有读参数表和不调用shell的特点。而如果要使用piped open() 和backticks,就无法保证不会用到shell。
如果你打算使用piped open 或 backticks,你得用如下的方法重新实现:
|
$pid = open(COMMAND, "-|");
die "Couldn't fork: $!" unless defined $pid;
if ($pid) {
@lines = <COMMAND>;
close(COMMAND);
} else {
exec("some", "program", "with", "args") or die
"execing: $!";
}
|
一般来说,即使你的PATH已经作了安全处理,给出所运行的程序的完整路径是个好主意。这就会避免了错误地调用了/usr/bin/boom 而不是/home/user/bin/boom这种情况的发生,因为在PATH中 /usr/bin 位于/home/usr/bin/boom.之前。