结构化查询语言(SQL)是一种用来和数据库交互的文本语言。SQL Injection就是利用某些数据库的外部接口将用户数据插入到实际的数据库操作语言(SQL)中,从而达到入侵数据库乃至操作系统的目的。他的产生主要是由于程序对用户输入的数据没有进行严格的过滤,导致非法数据库柴新建语句的的执行。
SQL注入如有很大的危害,攻击者可以利用它读取、修改或者删除数据库中的内容,获取数据库中的用户名和密码等敏感信息,甚至可以获取数据库管理员的权限,而且,SQL注入也很难防范。网站管理员无法通过安装系统补丁或者而进行简单的安全配置进行自我保护,一般的防火墙也无法拦截SQL Injection攻击。
下面的用户登录验证程序就是SQL注入的一个例子
创建用户表user CREATE TABLE user( userid int(11) NOT NULL auto_increment, username varchar(20) NOT NULL default '', password varchar(20) NOT NULL default '', PRIMARY KEY (userid) )ENGINE=MyISAM AUTO_INCREMENT=3; --Query OK, 0 rows affected (0.07 sec) 给用户表添加一条新记录 INSERT INTO `user` VALUES (1, 'angel', 'mypass'); --Query OK, 1 row affected (0.00 sec) 验证用户root登录localhost服务器 <?php $servername = "localhost"; $dbusername = "root"; $dbpassword = ""; $dbname = "injection"; mysql_connect($servername,$dbusername,$dbpassword) or die ("数据库连接失败"); $sql = "SELECT * FROM user WHERE username='$username' AND password='$password'"; $result = mysql_db_query($dbname, $sql); $userinfo = mysql_fetch_array($result); if (empty($userinfo)) { echo "登录失败"; } else { echo "登录成功"; } echo "<p>SQL Query:$sql<p>"; ?> 然后提交如下url http://127.0.0.1/injection/user.php?username=angel' or '1=1结果发现,这个 URL 可以成功登录系统,但是很显然这并不是我们预期的结果。同样也可以利用 SQL 的注释语句实现 SQL 注入,如下面的例子:
http://127.0.0.1/injection/user.php?username=angel'/* http://127.0.0.1/injection/user.php?username=angel'#因为在SQL语句中,/*或/#都可以将后面的语句注释掉
对SQL注入的隐患,一旦遭到入侵后果是很严重的,轻则获取数据信息,重则可以将数据非法修改。一下是在实际应用开发中的一些具体的防止SQL注入的措施
对Java,jsp开发的应用,可以使用PrepareStatement+Bind-variable来防止SQL注入,另外从PHP5开始,也在扩展MYSQLI中支持PrepareStatement,所以在使用这类语言进行数据库开发时,强烈建议PrepareStatement+Bind-variable来实现,而尽量不要使用拼接的SQL。
如下:
... String sql = "select * from user where username=? and password =?"; PrepareStatement ps = new PrepareStatement(sql); ps.setString(1,id); ps.setString(2,pwd); Resultset rs = ps.executeQuery(); ...很多应用程序接口都提供了对特殊字符进行转换的函数,恰当的使用这些函数,可以防止应用程序用户输入使应用程序生成不期望的语句。
MYSQL C API:使用mysql_real_escape_string()API调用Mysql++:使用escape和quote修饰符。PHP:使用mysql_real_escape_string()函数(适用于PH4.3.0版本)。从PHP开始,可以使用扩展的MYSQLI,这是对MySQL新特性的一个扩展支持,其中的一个而优点就是支持PrepareStatement。Perl DBI:使用placeholder或者quote()方法。Ruby DBI:使用placeholder或者quote()方法。如果现有的函数任然不能满足要求,则需要自己编写函数进行输入校验。输入验证是一个很复杂的问题。输入验证的验证途径可以分为以下几个部分:
整理数据使之变的有效。拒绝已知的非法输入。值接收已知的合法输入。所以如果想要获得最好的安全状态,目前最好的解决办法就是对用户提交或者可能改变的数据进行简单的分类,分别应用正则表达式来对用户提供的输入数据进行严格的检测和验证。
通常通过正则表达式来验证输入数据是否合法,已知的非法符号如下:
“’”、“;”、“=”、“(”、“)”、“/*”、“*/”、“%”、“+”、“”、“>”、“<”、“--”、“[”、“]”;