星期四, 三月 22, 2007

php_admin_value for security

看一个 PHP 程序:
$fp = fopen("/etc/passwd","r"); 
if($fp) {
echo 'ok!';
$result = fread($fp, 8192);
echo $result;
} else {
echo 'no!';
}
?>
通过 URL 运行这个 PHP 程序,会发现程序确实可以读到 /etc/passwd。这是一个危险的信号,我没有想到 PHP 会有这样的安全问题(这应该不是 Apache 的问题,因为 DocumentRoot 已经限制了根路径,而且又没有使用 FollowSymLink 选项)。这意味着一个 PHP 程序可以访问文件系统的任何地方!

当提供虚拟主机服务的时候,这个问题就会变得更加棘手,因为各个虚拟主机可能属于不同的用户,而在这种情况下,一个用户将可以毫无障碍的读取另一个用户的文件!

解决的办法是使用 PHP 的 safemode 中的 open_basedir 参数来进行限制,并且需要对每一个虚拟主机分别做不同的限制:
"<"VirtualHost *:80">" 
DocumentRoot "/var/www/html/docs/html"
php_admin_value open_basedir /var/www/html/docs/html/
"<"Directory "/var/www/html/docs/html"">"
Options Indexes
AllowOverride None
Order allow,deny
Allow from all
"<"/Directory">"
"<"/VirtualHost">"
也可以在 php.ini 中更改 open_basedir 参数来做一个全局的限制。如 open_basedir = /www/users:/tmp 等。

这种方法只是正对 mod_php 有效,对使用 CGI 方式(如 cgiwrap)则不行——如果没有使用 LoadModule mod_php,那么在 httpd.conf 中使用 php_admin_value 将使得 apache 无法启动。

但是如果是使用 mod_rewrite 方式建立的虚拟主机呢?