在escapeshellcmd
的php文档页面中有一个警告:
应该在整个命令字符串上使用escapeshellcmd() 仍允许攻击者传递任意数量的参数。对于 转义单个参数应该使用escapeshellarg()。
我从中可以理解:
谢谢你, 科斯明
答案 0 :(得分:6)
简而言之
假设您的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上测试过。在我看来,这是一个错误,因为数据的字面含义丢失了。因此,在完整字符串上使用escapeshellcmd相对更安全,因为它也会转义反斜杠'\',这是一个shell元字符:
$c = escapeshellcmd( $cmd . ' ' . escapeshellarg( $arg1 ) );
exec( $c . ' > output.txt'); // writes TEST\0ING to output.txt
这种方法的缺点是其他元字符也将被转义,并且必须由传递参数的程序($ cmd)转义。
请注意,我们没有在完整的命令字符串上使用escapeshellcmd。我们省略了'> output.txt'部分以便'>'不会逃脱。
<强>结论:强>
尽量避免将字符串作为命令行参数传递。而是将数据写入文件并从文件中读取。通过这种方式,您可以确保传递的数据保持不变。
如果您绝对需要将字符串作为命令行参数传递,请始终确保它们是字母数字。
如果您绝对需要将字符串作为命令行参数传递,则在完整字符串上使用escapeshellcmd相对更安全。
答案 1 :(得分:2)
所以我认为escapeshellcmd
会阻止运行多个命令。
escapeshellcmd()转义字符串中可能用于欺骗shell命令执行任意命令的任何字符。
escapeshellarg
是为了确保用户提供的参数只是一个参数。
escapeshellarg()在字符串周围添加单引号,并引用/转义任何现有的单引号,允许您将字符串直接传递给shell函数并将其视为单个安全参数。
基本上,如果你(你的程序)正在定义命令,你应该只需要在每个用户提供的参数上使用escapeshellarg
,但是如果用户指示命令(除非你有真正可靠的服务器权限设置)和参数。
免责声明:这只是我对文档的解释。
编辑:
我同意这里的文档非常混乱。我认为这个警告暗示将这个包装在一个完整的命令周围不会阻止用户使用这样的参数
actualArg -someEvilFlag
或
actualArg -someEvilFlag evilFlagArgument
答案 2 :(得分:1)
我会参考What's the difference between escapeshellarg and escapeshellcmd?,其中详细介绍了每一项优点。
我想要跟进,我会说接受这个用户输入并仅使用escapshellcmd将它扔到shell中可能会以任何方式结束。我将专注于清理和输入验证,并将上述函数用作此代码安全过程的“最后部分”。