SQL 注入是PHP应用中最常见的漏洞之一。引发这样一个SQL注入漏洞是开发者同时犯了两个错误导致的。如下:
1)是没有对输入的数据进行过滤(过滤输入)
2)还有一个是没有对发送到数据库的数据进行转义(转义输出)
这两个重要的步骤缺一不可,需要同时加以特别关注以减少程序错误。
对于密码方面,使用用户密码的MD5值原来是一个通行的做法,但现在并不是特别安全了。最近的研究表明MD5算法有缺陷,而且大量MD5数据库降低了MD5反向破解的难度。请访问http://md5.rednoize.com/ 查看演示(原文如此,山东大学教授王小云的研究表明可以很快的找到MD5的“碰撞”,就是可以产生相同的MD5值的不同两个文件和字串。MD5是信息摘要算法,而不是加密算法,反向破解也就无从谈起了。不过根据这个成果,在上面的特例中,直接使用md5是危险的。)。
为了确保密码有更高的安全性,我们可以在密码上额外的附上一段自定义的字符串,例如:
代码:
<?php
$str = 'SHIFLETT';
$password_hash = md5($str . md5($_POST['password'] . $str));
?>
SQL注入其实还是很容易避免的。正如前面所提及的,你必须坚持过滤输入和转义输出虽然两个步骤都不能省略,但只要实现其中的一个就能消除大多数的SQL注入风险。如果你只是过滤输入而没有转义输出,你很可能会遇到数据库错误(合法的数据也可能影响SQL查询的正确格式),但这也不可靠,合法的数据还可能改变SQL语句的行为。另一方面,如果你转义了输出,而没有过滤输入,就能保证数据不会影响SQL语句的格式,同时也防止了多种常见SQL注入攻击的方法。
转义用于向数据库发送的输出数据只要使用同一个函数即可。对于MySQL用户,可以使用函数mysql_real_escape_string( ):
代码:
<?php
$clean = array();
$mysql = array();
$clean['last_name'] = "O'Reilly";
$mysql['last_name'] = mysql_real_escape_string($clean['last_name']);
$sql = "INSERT
INTO user (last_name)
VALUES ('{$mysql['last_name']}')";
?>
尽量使用为你的数据库设计的转义函数。如果没有,使用函数addslashes()是最终的比较好的方法。
当所有用于建立一个SQL语句的数据被正确过滤和转义时,实际上也就避免了SQL注入的风险。
(注:关于SQL注入,不得不说的是现在大多虚拟主机都会把magic_quotes_gpc选项打开,在这种情况下所有的客户端GET和POST的数据都会自动进行addslashes处理,所以此时对字符串值的SQL注入是不可行的,但要防止对数字值的SQL注入,如用intval()等函数进行处理。但如果你编写的是通用软件,则需要读取服务器的magic_quotes_gpc后进行相应处理。)