注入往往是应用程序缺少对输入进行安全性检查所引起的。攻击者把一些包含指令的数据发送给解释器,解释器会把收到的数据转换成指令执行。常见的注入包括SQL注入、OS Shell、LDAP、XPath、Hibernate等,其中SQL注入在早期尤为常见。这种攻击所造成的后果往往很大,一般整个数据库的信息都能被读取或篡改,通过SQL注入,攻击者甚至能够获得包括管理员的权限。
1.什么是SQL注入
SQL注入是指利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,这是SQL注入的标准释义。SQL注入利用的是正常的HTTP服务端口,表面上看来和正常的Web访问没有区别,隐蔽性极强,不易被发现。下面举例说明。
原代码:update users set passwd=′foo′where login=′loginName′
在login="后面的"之间注入漏洞:quux′or login=′admin
结果:update users set passwd=′foo′where login=′quux′or login=′admin′
2.SQL注入的危害
SQL注入的主要危害包括:
1)未经授权状况下操作数据中的数据;
2)恶意篡改网页内容;
3)私自添加系统账号或是数据库使用者账号;
4)网页挂木马。
3.SQL注入的方法
SQL注入式攻击需要下面的条件。
(1)没有正确过滤转义字符
在用户的输入没有为转义字符过滤时,就会发生这种形式的注入式攻击,它会被传递一个SQL语句,这样就会导致应用程序的终端用户对数据库上的语句实施操作。比方说,下面的这行代码就演示了这种漏洞:
这种代码的设计目的是将一个特定的用户从其用户表中取出,但是,如果用户名被一个恶意的用户用一种特定的方式伪造,这个语句所执行的操作可能就不仅仅是代码的作者所期望的那样了。例如,将用户名变量(即username)设置为:′a′or′t′=′t′,此时原始语句发生了变化:
如果这种代码被用于一个认证过程,那么这个例子就能够强迫选择一个合法的用户名,因为赋值′t′=′t′永远是正确的。
在一些SQL服务器上,如在SQL Server中,任何一个SQL命令都可以通过这种方法被注入,包括执行多个语句。下面语句中的username的值将会导致删除“users”表,又可以从“data”表中选择所有的数据(实际上就是透露了每一个用户的信息)。
这就将最终的SQL语句变成下面这个样子:
其他的SQL执行不会将执行同样查询中的多个命令作为一项安全措施,这会防止攻击者注入完全独立的查询,不过却不会阻止攻击者修改查询。
(2)不正确的类型处理(Incorrect type handling)
如果一个用户提供的字段并非一个强类型,或者没有实施类型强制,就会发生这种形式的攻击。当在一个SQL语句中使用一个数字字段时,如果程序员没有检查用户输入的合法性(是否为数字型)就会发生这种攻击。例如:
从这个语句可以看出,作者希望a_variable是一个与“id”字段有关的数字。不过,如果终端用户选择一个字符串,就绕过了对转义字符的需要。例如,将a_variable设置为:1;DROP TABLE users,它会将“users”表从数据库中删除,SQL语句变成:
(3)数据库服务器中的漏洞
有的数据库服务器软件中存在着漏洞,如Mysql服务器中mysql_real_escape_string()函数漏洞。这种漏洞允许一个攻击者根据错误的统一字符编码执行一次成功的SQL注入式攻击。
(4)盲目SQL注入式攻击
当一个Web应用程序易于遭受攻击而其结果对攻击者却不可见时,就会发生所谓的盲目SQL注入式攻击。有漏洞的网页可能并不会显示数据,而是根据注入到合法语句中的逻辑语句的结果显示不同的内容。这种攻击相当耗时,因为必须为每一个获得的字节精心构造一个新的语句。但是一旦漏洞的位置和目标信息的位置被确立以后,一种称为Absinthe的工具就可以使这种攻击自动化。
(5)条件响应
有一种SQL注入迫使数据库在一个普通的应用程序屏幕上计算一个逻辑语句的值:
这会得到一个标准的页面,而语句
在页面易于受到SQL注入式攻击时,它有可能给出一个不同的结果。这样的注入证明盲目的SQL注入是可能的,它会使攻击者根据另外一个表中的某字段内容设计可以评判真伪的语句。
(6)条件性差错
如果WHERE语句为真,这种类型的盲目SQL注入会迫使数据库评判一个引起错误的语句,从而导致一个SQL错误。例如:
显然,如果用户Ralph存在的话,被零除将导致错误。
(7)时间延误
时间延误是一种盲目的SQL注入,根据所注入的逻辑,它可以导致SQL引擎执行一个长队列或者是一个时间延误语句。攻击者可以衡量页面加载的时间,从而决定所注入的语句是否为真。
4.SQL注入的防御手段
SQL注入往往是在程序员编写包含用户输入的动态数据库查询时产生的,但防范SQL注入的方法其实非常简单。程序员只要不再写动态查询,或防止用户输入包含能够破坏查询逻辑的恶意SQL语句,就能够防范SQL注入。下面将介绍防止SQL注入的一些非常简单的方法。
用以下Java代码作为示例:
在以上代码中,可以看到并未对变量customerName做验证,customerName的值可以直接附在query语句的后面传送到数据库执行,则攻击者可以将任意的SQL语句注入。
防范方法主要有如下几种:
(1)参数化查询
参数化查询是所有开发人员在做数据库查询时首先需要学习的,参数化查询迫使所有开发者首先要定义好所有的SQL代码,然后再将每个参数逐个传入,这种编码风格就能够让数据库辨明代码和数据。
参数化查询能够确保攻击者无法改变查询的内容,在下面修正过的例子中,如果攻击者输入了UserID是“′or′1′=′1”,参数化查询会去查找一个完全满足名字为′or′1′=′1的用户。
对于不同编程语言,有一些不同的建议:(www.xing528.com)
●Java EE——使用带绑定变量的PreparedStatement();
●.Net——使用带绑定变量的诸如SqlCommand()或OleDbCommand()的参数化查询;
●PHP——使用带强类型的参数化查询PDO(使用bindParam());
●Hibernate——使用带绑定变量的createQuery()。
Java示例:
C#.Net示例:
(2)使用存储过程
存储过程和参数化查询的作用一样,唯一的不同在于存储过程是预先定义并存放在数据库中,从而被应用程序调用的。
Java存储过程示例:
VB.NET存储过程示例:
(3)对所有用户输入进行转义
知道每个DBMS都有一个字符转义机制来告知DBMS输入的是数据而不是代码,如果将所有用户的输入都进行转义,那么DBMS就不会混淆数据和代码,也就不会出现SQL注入了。
当然,如果要采用这种方法,读者就需要对所使用的数据库转义机制,也可以使用现存的诸如OWASP ESAPI的escaping routines。ESAPI目前是基于MySQL和Oracle的转义机制,使用起来也很方便。一个Oracle的ESAPI的使用示例如下:
假设读者有一个要访问Oracle数据库的动态查询代码如下:
那么,读者就必须重写动态查询的第一行如下:
当然,为了保证自己代码的可读性,也可以构建自己的Oracle Encoder:
除了上面所说的三种防范方法以外,还可以用以下两种附加的方法来防范SQL注入,即最小权限法、输入验证白名单法。
(4)最小权限法
为了避免注入攻击对数据库造成的损害,可以把每个数据库用户的权限尽可能缩小,不要把DBA或管理员的权限赋予读者应用程序账户,在给用户权限时是基于用户需要什么样的权限,而不是用户不需要什么样的权限。当一个用户只需要读的权限时,就只给他读的权限;当用户只需要一张表的部分数据时,宁愿另建一个视图让他访问。
如果读者的策略都是用存储过程的话,那么仅允许应用程序的账户执行这些查询,而不给他们直接访问数据库表的权限。诸如此类的最小权限法能够在很大程度上保证数据库的安全。
(5)输入验证白名单法
输入验证能够在数据传递到SQL查询前就察觉到输入是否正确合法,采用白名单而不是黑名单则能在更大程度上保证数据的合法性。
5.对SQL注入的测试
对于测试人员来说,如何测试SQL注入漏洞是否存在呢?
首先,将SQL注入攻击分为以下三种类型。
1)Inband:数据经由SQL代码注入的通道取出,这是最直接的一种攻击,通过SQL注入获取的信息直接反映到应用程序的Web页面上。
2)Out-of-band:数据通过不同于SQL代码注入的方式获得(如通过邮件等)。
3)推理:这种攻击是说并没有真正的数据传输,但攻击者可以通过发送特定的请求,重组返回的结果从而得到一些信息。
不论是哪种SQL注入,攻击者都需要构造一个语法正确的SQL查询,如果应用程序对一个不正确的查询返回了一个错误消息,那么就很容易重新构造初始的查询语句的逻辑,进而也就能更容易地进行注入;如果应用程序隐藏了错误信息,那么攻击者就必须对查询逻辑进行逆向工程,即所谓的“SQL盲注”。
SQL注入测试一定要使用工具。一是因为工作效率的问题;二是因为人工很难构造出覆盖面广的盲注入的SQL语句。例如,当一个查询的where字句包含了多个参数,or或and的关系比较多时,简单的or 1=1或and 1=2是很难发现注入点的。
SQLmap是一种很好的SQL注入测试工具。它是使用python进行开发,没有UI界面的命令行工具,使用起来比较容易,并且有很详细的帮助文档。SQLmap根目录下的Sql-map.py是主程序,sqlmap.conf是配置文件。SQLmap的使用有以下两种方式。
1)在cmd中直接输入命令行。
2)在sqlmap.conf中配置命令行参数,然后在cmd中用sqlmap.py-c sqlmap.conf发起攻击。
建议使用第2种方式。这里仅列出sqlmap.conf中的几个命令。更详细的命令描述可参考doc目录下的readme.pdf。
命令1:
上述命令指定攻击的URL。
命令2:
上述命令含义为:如果是POST命令,则在data字段填上POST的数据。
命令3:
上述命令含义为:如果网站需要登录,则在cookie字段填上cookie数据。cookie数据可以用wireshark抓包得到。
命令4:
上述命令含义为:当发现注入点时,SQLmap会“嘀”的一声进行提示。
相关命令设置好以后,在命令行中输入sqlmap.py-c sqlmap.conf,即开始SQL注入测试。发现注入点后,则可以通过设置其他命令来尝试获取更多的后台数据库信息。
SQLmap功能非常多,例如获取数据用户名/密码/角色、查询数据库表内容、上传/下载文件、修改注册表等。有些功能需当前数据库用户在一定权限下才能完成。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。