SQL注入(SQL Injection)攻击具有很大的危害,攻击者可以利用它读取、修改或删除数据库内的数据,数据数据库中的用户名和密码等蜜柑信息,甚至可以获得数据库管理员的权限。如果能够再利用SQLServer扩展存储过程和自定义扩展存储过程来执行一些系统命令,攻击者还可以获得系统的控制权。而且,SQL Injection也很难防范。网站管理员无法通过安装系统补丁或者进行简单的安全配置进行自我保护,一般的防火墙也无法拦截SQL Injection攻击。
SQL Injection原理:
结构化查询语言(SQL)是一种用来和数据库交互的文本语言。SQL注入就是利用某些数据库的外部接口把用户数据插入到实际的数据库操作语言(SQL)中,从而达到入侵数据库乃至操作系统的目的。它的产生主要是由于程序对用户输入的数据没有进行严格的过滤,导致非法数据库查询语句的执行。
如下面的用户登录验证程序:
$sql = "SELECT * FROM user WHERE username='$username' AND password='$password'";
$result = mysql_db_query($dbname, $sql);
如果我们提交如下URL:
http://127.0.0.1/injection/user.php?username=angle' or '1=1
那么就可以成功登录系统,但是显然这并不是我们预期的,同样我们也可以利用SQL的注释语句实现SQL注入,如下面的例子:
http://127.0.0.1/injection/user.php?username=angle'/*
http://127.0.0.1/injection/user.php?username=angle' %23
这样就可以把后面的语句注释掉了!
说说这两种提交的不同之处,我们提交的第一句是利用逻辑运算,第二、三句是根据MySQL的特性,MySQL支持/*和#两种注释格式,所以我们提交的时候把后面的代码注释掉,值得注意的是由于编码问题,在IE地址栏里提交#会变成空的,所在我们在地址栏提交的时候,应该提交%23,才会变成#,就成功注释了,这个比逻辑运算简单的多了。
开发中可以采用的措施
1)prepareStatement + Bind-variable
对于Java和JSP开发的应用,可以使用prepareStatement + Bind-variable来防止SQL注入,另外从PHP5开始,也在扩展的mysqli中支持prepare statements,所以在使用这类语言作数据库开发时,强烈建议使用prepareStatement + Bind-variable来实现,而尽量不要使用拼接SQL。
2)使用应用程序提供的转换函数
很多应用程序接口都提供了对特殊字符进行转换的函数,恰当地使用这些函数,可以防止应用程序用户输入使用应用程序生成不期望的效果的语句的数值。
- MySQL C API:使用mysql_real_escape_string() API调用
- MySQL++:使用escape和quote修饰符
- PHP:使用mysql_real_escape_string()函数(适用与PHP4.3.0,之前的版本请使用mysql_escape_string(),PHP4.0.3之前的版本请使用addslashes())。从PHP5开始,可以使用扩展mysqli,这是对MySQL新特性的一个扩展支持,其中的一个优点就是支持prepared statements。
- Perl DBI:使用placeholders或者quotes()方法
- Ruby DBI:使用placeholders或者quote()方法
- Java JDBC:使用PrepareStatement和placeholders
3)自定义函数进行校验
如果现在的转换函数仍然不能满足需求,则需要自己编写函数进行输入校验。输入验证是一个很复杂的问题。输入验证的途径可以分为一下几种:
- 整理数据使之变得有效;
- 拒绝已知的非法输入;
- 只接收已知的合法的输入。
所以,如果想要获得最好的安全状态,目前最好的解决办法就是对用户提交或者可能改变的数据进行简单分类,分别应用正则表达式来对用户提供的输入数据进行严格的测试和验证。