Web安全初探-SQL注入

一、SQL注入

SQL注入是一种利用应用程序数据库层出现的安全漏洞的代码注入技术。通常在一些场景容易发生,比如用户输入的内嵌于SQL语句里的转义字符没有被正确的过滤掉或用户输入不是强类型导致异常的执行。SQL注入是注入型漏洞攻击中很常见的一种,注入式漏洞攻击在一种编程语言或脚本语言嵌入到另一种的任何时刻都可能发生。SQL注入是现在常用的应用层注入技术之一。

下图是通过扫描工具:WebCruiser-Web Vulnerability Scanner进行的SQL注入示例:

Web安全初探-SQL注入_第1张图片

二、SQL注入的种类

1、没有正确的过滤转义字符
在用户输入转义字符没有被过滤时,就会发生这种形式的注入式攻击。用户的输入会被传递给一个SQL语句,这样恶意用户就能对数据库上的语句实施操纵。下面的这行代码将会演示这种漏洞:

statement = "SELECT * FROM users WHERE name = '" + userName + "';"
这段代码用于从用户表中取出一个特定的用户,但如果用户名被一个恶意的用户用一种特定的方式伪造,这个语句所执行的操作可能就不仅仅是代码的作者所期望的那样了。例如,将用户名变量username设置为:
a' or 't'='t
对应的原始的SQL语句为:
SELECT * FROM users WHERE name = 'a' OR 't'='t';
如果这段代码被用于一个认证过程,那么这个例子就能够强迫系统选择一个合法的用户名,因为赋值 't'='t永远是正确的。
在一些SQL服务器上,如在SQL Server中,任何一个SQL命令都可以通过这种方法被注入,包括执行多个语句。将username赋值为下面语句的值会造成users表的删除,还会获取userinfo表的所有数据,导致用户信息的泄露。
 a';DROP TABLE users; SELECT * FROM userinfo WHERE 't' = 't
 这个输入最终执行的SQL语句为:
 SELECT * FROM users WHERE name = 'a';DROP TABLE users; SELECT *
 FROM userinfo WHERE 't' = 't';
多数SQL服务器实现允许一次调用执行多条语句,一些SQL APIs比如PHP的mysql_query()出于安全原因不允许此操作。这可以阻止攻击者注入完全独立的查询,而不能阻止他们修改查询。
2、不正确的类型处理
如果一个用户提供的字段并非一个强类型,或者没有检查类型约束,就会发生这种形式的攻击。当在一个SQL语句中使用一个数字字段时,如果程序员没有检查用户输入的合法性(是否为数字型)就会发生注入:
statement := "SELECT * FROM userinfo WHERE id = " + a_variable + ";"
从该语句可以看出,程序设计者希望a_variable是一个与“id”字段有关的数字,然而如果实际传入的是字符串,例如将a_variable设置为:
1;DROP TABLE users
将会删除掉users表,因为实际上最终执行的语句是:
SELECT * FROM userinfo WHERE id=1;DROP TABLE users;
3、数据库服务器的漏洞
有时候,数据库服务器软件本身也存在漏洞,如MySQL服务器的mysql_real_escape_string()函数漏洞。该漏洞允许攻击者利用错误的Unicode编码(统一字符编码)顺利的执行SQL注入攻击,尽管用户的输入已经被转码。这个bug在5.0.22版本才修复。
4、盲目SQL注入攻击
当一个web应用程序很容易受到SQL注入攻击,而攻击者看不到注入的结果时就会发生盲目SQL注入式攻击。有漏洞的网页可能并不会显示数据,而是根据注入到合法语句中的逻辑语句的结果显示不同的内容。这种攻击相当耗时,因为必须为每一个获得的字节精心构造一个新的语句。一旦漏洞的位置和目标信息确定下来,就可以通过一些软件将攻击自动化。

 4.1、条件响应

有一种SQL注入迫使数据库在一个普通的应用程序屏幕上计算一个逻辑语句的值:

SELECT booktitle FROM booklist WHERE bookId = 'OOk14cd' AND 1=1;
这会显示一个正常的页面,而语句
SELECT booktitle FROM booklist WHERE bookId = 'OOk14cd' AND 1=2;
在页面易于受到SQL注入式攻击时,它有可能给出一个不同的结果。
这样的注入可能会提示攻击者盲目SQL注入是可能的,它会使攻击者根据其他列或表的内容设计可以评判真伪的语句实施破坏。
 4.2、条件性错误

如果WHERE语句为真,这种类型的盲目SQL注入通过强迫数据库计算一个引起错误的语句来引发SQL错误,例如:

SELECT 1/0 FROM users WHERE username='Ralph'
显然,如果用户Ralph存在的话,被零除将导致错误。
 4.3、时间延迟

时间延误是一种盲目SQL注入,根据所注入的逻辑,它可以导致SQL引擎执行一个长队列或一个时间延迟语句。攻击者可以衡量页面加载的时间,从而判定注入的语句是否成功。

二、防御和检查SQL注入的手段
1、使用参数化的过滤性语句
  要防御SQL注入,用户的输入就绝对不能直接被嵌入到SQL语句中。恰恰相反,用户的输入必须进行过滤,或者使用参数化的语句。参数化的语句使用参数而不是将用户输入嵌入到语句中。在多数情况中,SQL语句可以被修正。然后,用户输入就被限于一个参数。

下面是一个使用Java和JDBC API的例子:

  PreparedStatement prep = conn.prepareStatement("SELECT * FROM USERS WHERE PASSWORD=?");
    prep.setString(1, pwd);
如何强制使用参数化语句?

从数据库级别强制:目前只有H2数据库支持强制使用参数化查询。
从代码级别强制:使用对象关系映射库避免写SQL代码的需要。ORM库可以从基于对象的代码中生成参数化的SQL语句。当然也可以通过代码复查来检查代码中是否存在非参数化SQL。
2、转码
一种直接的,但易出错的避免注入的方式是转义危险的字符。它易出错的原因之一是,它是一种鲁棒性低于白名单的黑名单。比如,参数中每次出现单引号(')时必须替换为两个单引号(''),以此构成有效的SQL字符串。PHP中,在发送SQL查询之前,常用mysql_real_escape_string函数转码查询参数:

$query = sprintf("SELECT * FROM Users where UserName='%s' and
Password='%s'",
mysql_real_escape_string($Username),
mysql_real_escape_string($Password));
mysql_query($query);
对于查询参数需要过滤对数据库造成破坏的字段,比如update,delete,drop等。
3、防范SQL注入,还要避免出现一些详细的错误消息,因为黑客们可以利用这些消息。要使用一种标准的输入确认机制来验证所有的输入数据的长度、类型、语句、企业规则等。
4、使用Web漏洞扫描工具
WebCruiser-Web Vulnerability Scanner,是一款简单但强大的web安全扫描工具。它有个爬虫和漏洞扫描器。它不仅支持扫描网站,还能验证web漏洞,比如SQL注入,跨站脚本攻击,XPath注入等。所以,WebCruiser也是一个SQL注入器,Xpath注入器和跨站脚本工具。下载地址: http://sec4app.com/
5、最后一点,企业要在Web应用程序开发过程的所有阶段实施代码的安全检查。首先,要在部署Web应用之前实施安全测试,这种措施的意义比以前更大、更深远。企业还应当在部署之后用漏洞扫描工具和站点监视工具对网站进行测试。

你可能感兴趣的:(数据库,sql注入,安全漏洞)