PHP 安全及相关
0gPCAvZXRjL3Bhc3N3ZA=="); system($code);'' [user@localhost]# .zip /tmp/phpY4iatI 如你所见,这个看起来无害的PHP程式突然变成执行任意shell命令和其他PHP程式的后门。虽然这个例子只会在路径下有CLI版本的PHP的系统上有效,但是用这种技术可以通过其他的方法来达到同样的效果。 对抗系统调用攻击 这里的关键仍然是,来自用户的输入,不管内容如何,都不应该相信!问题仍然是如何在使用系统调用时(除了根本不使用它们)避免类似的情况出现。为了对抗这种类型的攻击,PHP提供了两个函数,escapeshellarg() 和 escapeshellcmd()。 escapeshellarg()函数是为了从用作系统命令的参数的用户输入(在我们的例子中,是zip命令)中移出含有潜在危险的字符而设计的。这个函数的语法如下: escapeshellarg($string) $string所在处是用于过滤的输入,返回值是过滤后的字符。执行时,这个函数将在字符两边添加单引号,并转义原来字符串中的单引号(在其前边加上)。在我们的例程中,如果我们在执行系统命令之前加上这些行: $cmp_name = escapeshellarg($cmp_name); $tmp_name = escapeshellarg($tmp_name); 我们就能通过确保传递给系统调用的参数已经处理,是一个没有其他意图的用户输入,以规避这样的安全风险。 escapeshellcmd()和escapeshellarg()类似,只是它只转义对底层操作系统有特殊意义的字符。和escapeshellarg()不同,escapeshellcmd()不会处理内容中的空白格。举个实例,当使用escapeshellcmd()转义时,字符 $string = "''hello, world!'';evilcommand" 将变为: ''hello, world'';evilcommand 如果这个字符串用作系统调用的参数它将仍然不能得到正确的结果,因为shell将会把它分别解释为两个分离的参数: ''hello 和 world'';evilcommand。如果用户输入用于系统调用的参数列表部分,escapeshellarg()是一个更好的选择。 保护上传的文件 在整篇文章中,我一直只着重讲系统调用如何被恶意用户劫持以产生我们不希望结果。 但是,这里还有另外一个潜在的安全风险值得提到。再看到我们的例程,把你的注意力集中在下边的行上: $tmp_name = Copyright © 2008 chengduxinxi.com All Rights Reserved PHP编程开发 由朝夕网络维护
$cmp_name = dirname( Copyright © 2008 chengduxinxi.com All Rights Reserved PHP编程开发 由朝夕网络维护
"/{ Copyright © 2008 chengduxinxi.com All Rights Reserved PHP编程开发 由朝夕网络维护
$filename = basename($cmp_name); if (file_exists($tmp_name)) { 上边片断中的代码行导致的一个潜在安全风险是,最后一行我们判断上传的文件是否实际存在(以临时文件名$tmp_name存在)。 这个安全风险并不来自于PHP自身,而在于保存在$tmp_name中的文件名实际上根本不是一个文件,而是指向恶意用户希望访问的文件,比如,/etc/passwd。 为了防止这样的情况发生,PHP提供了is_uploaded_file()函数,它和file_exists()一样,但是它还提供文件是否真的从客户机上上传的检查。 在绝大多数情况下,你将需要移动上传的文件,PHP提供了move_uploaded_file()函数,来配合is_uploaded_file()。这个函数和rename()一样用于移动文件,只是它会在执行前自动检查以确保被移动的文件是上传的文件。move_uploaded_file()的语法如下: move_uploaded_file($filename, $destination); 在执行时,函数将移动上传文件$filename到目的地$destination并返回一个布尔值来标志操作是否成功。 注: John Coggeshall 是一位PHP顾问和作者。从他开始为PHP不眠已经5年左右了。 英文原文:http://www.onlamp.com/pub/a/php/2003/08/28/php_foundations.html |
