SQL注入(SQL Injection)是利用某些数据库的外部接口将数据插入到实际的数据库操作语言(SQL)当中,从而达到入侵数据库乃至操作系统的目的。它的产生主要是由于程序对用户输入的数据没有进行严格的过滤,导致非法数据库查询语句的执行。
SQL注入
下面的用户登陆验证程序就是SQL注入的一个例子(以PHP程序举例)
创建用户表user:
给用户表user添加一条用户记录:
验证用户root登录的localhost服务器:
然后提交如下URL:
结果发现,这个URL可以成功登陆。同样也可以利用SQL的注释语句实现SQL注入,例如:
因为在SQL语句中,” /* “或者” # “都可以将后面的语句注释掉。这样上述语句就可以通过这两个注释符中任意一个将后面的语句给注释掉,结果导致只根据用户名而没有密码的URL都成功进行了登录。利用” or “和注释符的不同之处在于,前者是利用逻辑运算,而后者是根据MySQL的特性,这个比逻辑运算简单的多。
应对措施
PrepareStatement+Bind-variable
对Java、JSP开发的应用,可以使用PrepareStatement+Bind-variable来防止SQL注入,尽量不要使用拼接的SQL。
Bind-variable(绑定变量):查询通常只是因为改变where子句中的内容而产生不同的结果。为了在这种情况下避免硬解析,需要使用绑定变量。它是用户放入查询中的占位符,它会告诉MySQL或者Oracle”我会提供一个值放到这里”,一般在procedure or function中使用,可以优化共享池的使用。
使用应用程序提高的转换函数
很多应用程序接口都提供了对特殊字符进行转换的函数,恰当的使用这些函数,可以防止应用程序用户输入使应用程序生成不当期望的语句。
- MySQL C API:使用mysql_real_escape_string()API调用。
- MySQL++:使用escape和quote修饰符。
- PHP:使用mysql_real_escape_string()函数(适用于PHP 4.3.0版本)
- Perl DBI:使用placeholders或者quote()方法。
- Ruby DBI:使用placeholders或者quote()方法。
自定义函数进行校验
如果现有的转换函数仍然不能满足要求,则需要自己编写函数进行输入校验。输入验证的途径可以分为以下几种:
- 整理数据使之变得有效。
- 拒绝已知的非法输入。
- 只接受已知的合法输入。
所以如果想要获得最好的安全状态,目前最好的解决方法就是对用户提交或者可能改变的数据进行简单分类,分别应用正则表达式来对用户提供的输入数据进行严格的检测和验证。