PHP安全备忘录

admin 发表于 [PHP] 分类,标签: PHP代码 PHP自定义函数 PHP安全
1

一、PHP变量漏洞防范

1、所有变量进行初始化
2、在使用extract()分解由用户提交的数据组成的数组时,一定要设定第二个参数为:EXTR_SKIP
例如:extract($_REQUEST,EXTR_SKIP);
3、使用define函数定义常量
4、严格控制变量的数据类型

二、文件包含漏洞防范

使用的文件名可以使用define函数定义的常量,或用户不能直接修改的变量。

三、SQL注入攻击防范

对用户提交的数据进行转义和过滤:

<?php
//  @filename phpsafe.php
//  @version 1.0
//  @author admpub.com
//  @contact podos@vip.qq.com
//  @update 2010-11-16
//  @comment PHP Safe Functions
// =============================
function adm_escape_filter($str, $allowHtml = true) {
	static $func = '';
	if (empty($func)) {
		if (function_exists('mysql_real_escape_string') && $GLOBALS['db']) {
			// 使用本函数之前,请确认已经进行过数据库连接。
			$func = 'mysql_real_escape_string'; //转义字符有:\x00, \n, \r, \, ', " and \x1a
		} else {
			$func = 'addslashes'; //转义字符有:',",\, NULL
		}
	} 

	if (is_array($str)) {
		foreach($str AS $k => $v) {
			if($k!='GLOBALS'&&!ereg('^_[A-Z]+$',$k)) {
                $str[$k] = adm_escape_filter($v, $allowHtml);
            }else{
                unset($str[$k]);
            }
		}
	} else {
		$str = $func($str);
        $str = adm_filter($str,$allowHtml);
	}
	return $str;
} 

function adm_filter($str, $allowHtml = true, $break = 0) {
	if (is_array($str)) {
		foreach($str AS $k => $v) {
            if($k!='GLOBALS'&&!ereg('^_[A-Z]+$',$k)) {
                $str[$k] = adm_filter($v, $allowHtml, $break);
            }else{
                unset($str[$k]);
            }
		}
	} else {
        if(!$allowHtml) {
            $str = htmlspecialchars($str);
        }
		if ($break) {
			if (preg_match('{(select|insert|update|delete|/\*|union|into|load_file|outfile|0xbf)}is', $str, $fd)) {
				exit('<script type="text/javascript">
            <!--
                alert("\u60A8\u63D0\u4EA4\u7684\u6570\u636E\u4E2D\u5305\u542B\u975E\u6CD5\u5B57\u7B26\u300E' . $fd[1] .'\n('.$str.')'. '\u300F\uFF0C\u8BF7\u4FEE\u6539\u3002");
            //-->
            </script>');
			}
		} else {
			$str = preg_replace_callback('{(select|insert|update|delete|/\*|union|into|load_file|outfile|0xbf)}is', 'adm_preg_callback', $str);
		}
	}
    return $str;
} 

function adm_preg_callback($p) {
	if ($p[1]) {
        $len=strlen($p[1]);
        if($len>1) {
		    $p[1] = substr($p[1], 0, $len-1) . ' ' . substr($p[1], -1);
        }else{
            $p[1] = '';
        }
	}
	return $p[1];
} 

function adm_t($p,$t='i') {
	switch($t){
    case 'i'://整数
        $p = preg_replace('{[^0-9]+}is','',$p);
        $p = intval($p);
     break;
     case 'a'://字母
        $p = preg_replace('{[^a-z]+}is','',$p);
     break;
     case 's'://字符串
        $p = strval($p);
     break;

     case 'aiu'://字母数字下划线
     default:
         $p = preg_replace('{[^a-z0-9_]+}is','',$p);
    }
	return $p;
} 

if (!defined('ADM_GPC_QUOTES')) {
	define('ADM_GPC_QUOTES', get_magic_quotes_gpc());
}
if ($_REQUEST) {
    if ($_COOKIE) {
		$_COOKIE = ADM_GPC_QUOTES ? adm_filter($_COOKIE, false) : adm_escape_filter($_COOKIE, false);
	}
	if ($_POST) {
		$_POST = ADM_GPC_QUOTES ? adm_filter($_POST) : adm_escape_filter($_POST);
	}
	if ($_GET) {
		$_GET = ADM_GPC_QUOTES ? adm_filter($_GET, false) : adm_escape_filter($_GET, false);
	}
    $_REQUEST = @array_merge($_COOKIE,$_POST,$_GET);
    extract($_REQUEST,EXTR_SKIP);
}
if($_FILES) {
    $_FILES = ADM_GPC_QUOTES ? adm_filter($_FILES, false) : adm_escape_filter($_FILES, false);
}
$_SERVER = adm_escape_filter($_SERVER, false);

将以上代码保存为phpsafe.php,并在所有脚本中包含本文件。

下载:phpsafe.zip

SQL注入攻击是黑客攻击网站最常用的手段。如果你的站点没有使用严格的用户输入检验,那么常容易遭到SQL注入攻击。SQL注入攻击通常通过给站点数据库提交不良的数据或查询语句来实现,很可能使数据库中的纪录遭到暴露,更改或被删除。

为了防止SQL注入攻击,PHP自带一个功能可以对输入的字符串进行处理,可以在较底层对输入进行安全上的初步处理,也即Magic Quotes。(php.ini magic_quotes_gpc)。如果magic_quotes_gpc选项启用,那么输入的字符串中的单引号,双引号和其它一些字符前将会被自动加 上反斜杠\。

但Magic Quotes并不是一个很通用的解决方案,没能屏蔽所有有潜在危险的字符,并且在许多服务器上Magic Quotes并没有被启用。所以,我们还需要使用其它多种方法来防止SQL注入。

许多数据库本身就提供这种输入数据处理功能。例如PHP的MySQL操作函数中有addslashes()、 mysql_real_escape_string()、mysql_escape_string()等函数,可将特殊字符和可能引起数据库操作出错的字 符转义。那么这三个功能函数之间有什么却别呢?下面我们就来详细讲述下。

虽然国内很多PHP程序员仍在依靠addslashes防止SQL注入,还是建议大家加强中文防止SQL注入的检查。addslashes的问题在 于黑客 可以用0xbf27来代替单引号,而addslashes只是将0xbf27修改为0xbf5c27,成为一个有效的多字节字符,其中的0xbf5c仍会 被看作是单引号,所以addslashes无法成功拦截。

当然addslashes也不是毫无用处,它是用于单字节字符串的处理,多字节字符还是用mysql_real_escape_string吧。

另外对于php手册中get_magic_quotes_gpc的举例:
if (!get_magic_quotes_gpc()) {
$lastname = addslashes($_POST[‘lastname’]);
} else {
$lastname = $_POST[‘lastname’];
}
最好对magic_quotes_gpc已经开放的情况下,还是对$_POST[’lastname’]进行检查一下。

再说下mysql_real_escape_string和mysql_escape_string这2个函数的区别:
mysql_real_escape_string 必须在(PHP 4 >= 4.3.0, PHP 5)的情况下才能使用。否则只能用 mysql_escape_string ,两者的区别是:mysql_real_escape_string 考虑到连接的当前字符集,而mysql_escape_string 不考虑。

总结一下:

* addslashes() 是强行加\;
* mysql_real_escape_string() 会判断字符集,但是对PHP版本有要求;
* mysql_escape_string不考虑连接的当前字符集。

PHP中的变量除了来源于$_GET、$_POST、$_FILES、$_COOKIE的提交之外,还来源 于$_SERVER、$_ENV、$_SESSION等,其 中$_ENV和$_SESSION我们不能很方便地控制和自由提交,所以只剩下一个$_SERVER变量了。而$_SERVER变量包括的内容除了来自服 务器本身外,还有很大一部分来源于用户提交的HTTP请求,比如下面的代码。

QUERY_STRING        //用户Get方法提交时的查询字符串
HTTP_REFERER        //用户请求的来源变量,在一些程序取得用户访问记录时用得比较多
HTTP_USER_AGENT        //用户的浏览器类型,也用于用户的访问记录的取得
HTTP_HOST        //提交的主机头等内容
HTTP_X_FORWARDED_FOR        //用户的代理主机的信息

如上的变量在PHP5.0以下是受magic_quotes_gpc选项影响的,当magic_quotes_gpc选项为ON时,该数组中的元字 符等内容就会做转义处理;为OFF时,用户的提交就会不做任何处理,直接送到数组中。现在的大部分稍安全一点的程序都已经注意到来 自$_GET、$_POST、$_FILES以及$_COOKIE的变量的安全性,但是$_SERVER变量呢?尽管在magic_quotes_gpc 为ON的情况下,这些变量可能受到保护。但是很明显,忽视$_SERVER的结果就是安全隐患的增加,你就可以去寻找程序取得$_SERVER的地方,很 可能就是脆弱点了!
所以,我们要注意任何的从客户端输入的变量,因为所有的输入都是有害的。

另外将管理员用户名和密码都采取md5加密,这样就能有效地防止了php的注入。
还有服务器和mysql也要加强一些安全防范。

四、对于linux服务器的安全设置:

加密口令,使用“/usr/sbin/authconfig”工具打开密码的shadow功能,对password进行加密。
禁止访问重要文件,进入linux命令界面,在提示符下输入:
#chmod 600 /etc/inetd.conf //改变文件属性为600
#chattr +I   /etc/inetd.conf     //保证文件属主为root
#chattr –I   /etc/inetd.conf     // 对该文件的改变做限制
禁止任何用户通过su命令改变为root用户
在su配置文件即/etc/pam.d/目录下的开头添加下面两行:
Auth   sufficient   /lib/security/pam_rootok.so debug
Auth   required   /lib/security/pam_whell.so group=wheel
删除所有的特殊帐户
#userdel   lp等等 删除用户
#groupdel lp等等 删除组
禁止不使用的suid/sgid程序
#find / -type f \(-perm -04000   - o –perm -02000 \) \-execls –lg {} \;

1 条评论

发表我的评论