escapeshellcmd的php文档页面中有一个警告:
escapeShellcmd()应该用于整个命令字符串,它
仍然允许攻击者传递任意数量的参数。为了
应改用转义单个参数escapeShellarg()。
从这里我能明白什么:
我是否应该始终使用escapeshellcmd转义整个命令字符串,包括已经用escpaeshellarg转义的参数?
我应该只转义不是参数的命令项吗(如果你问我,这是唯一合乎逻辑的事情)?
我应该忽略这个可疑的警告吗?这个警告会让人们更加困惑这两个函数是如何相互补充的?
谢谢您,
科斯明

最佳答案

简而言之
escapeshellarg:用于用单引号括起参数,并在参数中转义引号。
escapeShellcmd:用于转义shell元字符,即,等
假设您的php版本依赖bash执行命令,我们可以从bash manual中了解到,
将字符括在单引号中会保留引号中每个字符的文字值。单引号不能出现在单引号之间,即使前面有反斜杠。
因此,我们可以得出这样的结论:创建命令的以下方式应该足够了:

$c = escapeshellcmd( $cmd ) . ' ' . escapeshellarg( $arg1 );

但是,如果需要将$C传递给以下函数之一,这可能会给您带来问题:exec、system、passthru等。经验分析表明,这些函数可以评估某些字符。例如,请尝试以下操作:
$cmd = 'echo';
$arg = 'TEST\0ING'; // Since we are using single quotes, \0 shouldn't be evaluated as a null byte char
$c = escapeshellcmd( $cmd ) . ' ' . escapeshellarg( $arg1 ); // echo 'TEST\0ING'
exec( $c . ' > output.txt'); // writes TEST without the ING to output.txt

exec函数将“\0”计算为空字节字符,因此output.txt将只包含不超过“\0”的数据。这已经在运行php 5.4.6的ubuntu上测试过了。在我看来,这是一个bug,因为数据的字面意义丢失了。因此,对完整字符串使用escapeShellcmd相对更安全,因为它还将转义反斜杠“\”,反斜杠是shell元字符:
$c = escapeshellcmd( $cmd . ' ' . escapeshellarg( $arg1 ) );
exec( $c . ' > output.txt'); // writes TEST\0ING to output.txt

这种方法的缺点是,其他元字符也将被转义,并且必须由传递参数的程序($cmd)取消转义。
注意,我们没有对完整的命令字符串使用escapeShellcmd。我们省略了“>output.txt”部分,这样“>”就不会被转义。
结论:
尽量避免将字符串作为命令行参数传递。相反,将数据写入文件并从文件中读取。这样可以确保传递的数据保持不变。
如果绝对需要将字符串作为命令行参数传递,请始终确保它们是字母数字的。
如果绝对需要将字符串作为命令行参数传递,则对完整字符串使用escapeShellcmd相对更安全。

08-28 06:55