在php文档页面中escapeshellcmd有一个警告:
应该在整个命令字符串上使用escapeshellcmd(),它仍然允许攻击者传递任意数量的参数.对于转义单个参数,应该使用escapeshellarg().
我从中可以理解的是:
谢谢你,Cosmin
简而言之
假设您的php版本依赖于bash执行命令,我们从bash手册中知道,
用单引号括起字符可以保留引号中每个字符的字面值.单引号之间可能不会出现单引号,即使前面有反斜杠也是如此.
因此,我们可以得出以下结论:创建命令的方法应该足够:
$c = escapeshellcmd( $cmd ) . ' ' . escapeshellarg( $arg1 );
Run Code Online (Sandbox Code Playgroud)
但是,如果您需要将$ 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
Run Code Online (Sandbox Code Playgroud)
exec函数将'\ 0'计算为空字节字符,因此output.txt只包含数据'0'.这已在运行PHP 5.4.6的Ubuntu上测试过.在我看来,这是一个错误,因为数据的字面含义丢失了.因此,在完整字符串上使用escapeshellcmd相对更安全,因为它也会转义反斜杠'\',这是一个shell元字符:
$c = escapeshellcmd( $cmd . ' ' . escapeshellarg( $arg1 ) );
exec( $c . ' > output.txt'); // writes TEST\0ING to output.txt
Run Code Online (Sandbox Code Playgroud)
这种方法的缺点是其他元字符也将被转义,并且必须由传递参数的程序($ cmd)转义.
请注意,我们没有在完整的命令字符串上使用escapeshellcmd.我们省略了'> output.txt'部分,以便'>'不会被转义.
结论:
尽量避免将字符串作为命令行参数传递.而是将数据写入文件并从文件中读取.这样,您可以确保传递的数据保持不变.
如果您绝对需要将字符串作为命令行参数传递,请始终确保它们是字母数字.
如果您绝对需要将字符串作为命令行参数传递,则在完整字符串上使用escapeshellcmd相对更安全.