防止SQL
Injection
>>
安全配置
php和apache的配置,主要用到php.ini和httpd.conf,而此文我们主要用到的是php.ini的配置。
1.为了安全起见我们一般都打开php.ini里的安全模式,即让safe_mode = On。
2.还有一个就是返回php执行错误的display_errors
这会返回很多有用的信息,所以我们应该关闭之,即让display_errors=off
关闭错误显示后,php函数执行错误的信息将不会再显示给用户。
3.在php的配置文件php.ini中还有一个非常重要的配置选项magic_quotes_gpc,高版本的默认都是magic_quotes_gpc=On,只有在原来的古董级的php中的默认配置是magic_quotes_gpc=Off,可是古董的东西也有人用的哦!当php.ini中magic_quotes_gpc=On的时候会有什么情况发生哩,不用惊慌,天是塌不下来的啦!它只是把提交的变量中所有的
' (单引号), " (双引号), \ (反斜线) 和
空字符会自动转为含有反斜线的转义字符,例如把'变成了\',把\变成了\\。
>>
初始化你的变量
我们看下面的代码:
if ($admin)
{
echo '登陆成功!';
include('admin.php');
}
else
{
echo '你不是管理员,无法进行管理!';
}
我们看上面的代码好像是能正常运行,没有问题,那么假如我提交一个非法的参数过去,那么效果会如何呢?比如我们的这个页是
http://www.traget.com/login.php,那么我们提交:http://www.target.com/login.php?
admin=1,呵呵,你想一想,我们是不是直接就是管理员,可以直接进行管理了?
当然,可能你会觉得不会犯这么简单错的错误,可最近暴出来的phpwind
1.3.6论坛漏洞,导致能够直接拿到管理员权限,就是因为有个$skin变量没有初始化,导致了后面一系列问题。
那么我们如何避免上面的问题呢?首先,从php.ini入手,把php.ini里面的register_global =
off,就是不是所有的注册变量为全局,那么就能避免了。但是,我们不是服务器管理员,只能从代码上改进了,那么我们如何改进上面的代码呢?我们改写如
下:
$admin = 0; // 初始化变量
if ($_POST['admin_user'] &&
$_POST['admin_pass'])
{
// 判断提交的管理员用户名和密码是不是对的相应的处理代码
// ...
$admin = 1;
}
else
{
$admin = 0;
}
if ($admin)
{
echo '登录成功!';
include('admin.php');
}
else
{
echo '你不是管理员,无法进行管理!';
}
那么这时候你再提交http://www.target.com/login.php?admin=1就不好使了,因为我们在一开始就把变量初始化为
$admin = 0 了,那么你就无法通过这个漏洞获取管理员权限。
>> 检查用户提交的值的类型
从前面的讨论中我们看到,迄今为止,SQL注入的主要来源往往出在一个意料之外的
表单入口上。然而,当你经由一个表单向用户提供机会提交某些值时,你应该有相当的优势来确定你想取得什么样的输入内容-这可以使得我们比较容易地检查用户
入口的有效性。在以前的文章中,我们已经讨论过这样的校验问题;所以,在此,我们仅简单地总结当时我们讨论的要点。如果你正在期望一个数字,那么你可以使
用下面这些技术之一来确保你得到的真正是一个数字类型:
· 使用is_int()函数(或is_integer()或is_long())。
· 使用gettype()函数。
· 使用intval()函数。
· 使用settype()函数。
为了检查用户输入内容的长度,你可以使用strlen()函数。为了检查一个期望的时间或日期是否有效,你可以使用strtotime()函数。它几乎
一定能够确保一位用户的入口中没有包含分号字符(除非标点符号可以被合法地包括在内)。你可以借助于strpos()函数容易地实现这一点,如下所示:
if( strpos( $variety, ';' ) ) exit ( "$variety is
an invalid value for variety!" );
正如我们在前面所提到的,只要你仔细分析你的用户输入期望,那么,你应该能够很容易地检查出其中存在的许多问题。
>>
从你的查询中滤去每一个可疑字符
尽管在以前的文章中,我们已经讨论过如何过滤掉危险字符的问题;但是在此,还是让我们再次简单地强调并归纳一下这个问题:
·
不要完全指望magic_quotes_gpc指令或它的"幕后搭挡"-addslashes()函数,此函数在应用程序开发中是被限制使用的,并且此函数还要求使用额外的步骤-使用stripslashes()函数。
· 相比之下,mysql_real_escape_string()函数更为常用,但是也有它自己的缺点。
>>
从代码去入手
SQL注射应该是目前危害最大的攻击方法了,包括最早的ASP到PHP,都是国内这两年流行的技术,基本原理就是通过对提交变量的不过滤形成注入点然后使恶意用户能够提交一些SQL查询语句,导致重要数据被窃取、数据丢失损坏,或者直接被入侵者拿到后台管理权限。
我们既然了解了基本的注射入侵的方式,那么我们如何去防范呢?这个就应该我们从代码去入手了。
我们知道Web上提交数据有两种方式,一种是GET、一种是POSTT,那么很多常见的SQL注射就是从GET方式入手的,而且注射的语句里面一定包含一
些SQL语句,SQL语句有四大关键词:select、update、delete、insert。如果我们在提交的数据中进行过滤是不是能够避免这些问
题呢?
于是我们使用正则就构建如下函数:
function inject_check($sql_str)
{
return
eregi('select|insert|update|delete|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile',
$sql_str); // 进行过滤
}
函数里把“select,insert,update,delete, union, into, load_file,
outfile
function verify_id($id=null)
{
if (!$id) { exit('没有提交参数!'); } // 是否为空判断
elseif (inject_check($id)) { exit('提交的参数非法!'); } // 注射判断
elseif (!is_numeric($id)) { exit('提交的参数非法!'); } // 数字判断
$id = intval($id); // 整型化
return $id;
}
呵呵,那么我们就能够进行校验了,于是我们上面的程序代码就变成了下面的:
if (inject_check($_GET['id']))
{
exit('你提交的数据非法,请检查后重新提交!');
}
else
{
$id = verify_id($_GET['id']); // 这里引用了我们的过滤函数,对$id进行过滤
echo '提交的数据合法,请继续!';
}
?>
好,问题到这里似乎都解决了,但是我们有没有考虑过Post提交的大批量的数据呢?比如一些字符可能会对数据库造成危害,比如“_”,“%”,这些字符都
有特殊意义,那么我们如果进行控制呢?还有一点,就是当我们的php.ini里面的“magic_quotes_gpc =
off”的时候,那么提交的不符合数据库规则的数据都是不会自动在前面加“\”的,那么我们要控制这些问题,于是构建如下函数:
function str_check( $str )
{
if (!get_magic_quotes_gpc()) // 判断magic_quotes_gpc是否打开
{
$str = addslashes($str); // 进行过滤
}
$str = str_replace("_", "\_", $str); // 把 '_'过滤掉
$str = str_replace("%", "\%", $str); // 把' % '过滤掉
return $str;
}
OK,我们又一次的避免了服务器被沦陷的危险。
最后,再考虑提交一些大批量数据的情况,比如发贴,或者写文章、新闻,我们需要一些函数来帮我们过滤和进行转换,再上面函数的基础上,我们构建如下函数:
function post_check($post)
{
if (!get_magic_quotes_gpc()) // 判断magic_quotes_gpc是否为打开
{
$post = addslashes($post); //
进行magic_quotes_gpc没有打开的情况对提交数据的过滤
}
$post = str_replace("_", "\_", $post); // 把 '_'过滤掉
$post = str_replace("%", "\%", $post); // 把' % '过滤掉
$post = nl2br($post); // 回车转换
$post= htmlspecialchars($post); // html标记转换
return $post;
}
在脚本编程的时候,一定要养成良好的编程习惯,例如本文所说的对变量进行初始化,同时注意变量的过滤,变量对整个系统的安全性起了很重要的作用。希望这些点滴能让你养成更好的习惯