在 escapeshellcmd
的 php 文档页面中有一个警告:
escapeshellcmd() should be used on the whole command string, and it still allows the attacker to pass arbitrary number of arguments. For escaping a single argument escapeshellarg() should be used instead.
我要从中理解什么:
- 我是否应该始终使用 escapeshellcmd 转义整个命令字符串,包括已经使用 escpaeshellarg 转义的参数?
- 我是否应该只转义不是参数的命令项(如果你问我,唯一合乎逻辑的做法)?
- 我是否应该忽略这个可疑的警告,它会更加混淆这两个功能如何相互补充?
谢谢, 科斯明
最佳答案
简而言之
- escapeshellarg: 用于用单引号将参数括起来,并转义参数中的引号。
- escapeshellcmd: 用于转义 shell 元字符,即 <,>,|等等
假设您的 php 版本依赖 bash 来执行命令,我们从 bash manual 中得知,
Enclosing characters in single quotes preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash.
因此,我们可以得出结论,以下创建命令的方式应该足够了:
$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 相对更安全。
关于php - escapeshellcmd警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15577949/