应用安全系列之一:SQL注入

       本系列文章主旨在于介绍一些漏洞类型产生的基本原理,探索最基础的解决问题的措施,不排除有些语言或者系统提供的安全的API可以更好地更直接地解决问题,也不排除可以严格地输入验证来解决。

        根据IT研究与顾问咨询公司Gartner统计数据显示,75%的黑客攻击发生在应用层。而由NIST的统计显示92%的漏洞属于应用层而非网络层,52%的网站应用程序都存在SQL注入、XSS跨站脚本和输入验证问题。注入攻击产生的后果比较严重,轻则导致数据泄露,严重的会导致数据被篡改,根伟严重的可能会导致DOS攻击或者主机被接管。由于注入攻击容易被利用而且导致的后果是非严重,因此,注入攻击已经连续多次排在OWASP TOP 10的第一名,在CWE的排名这种,也一直名列前茅。

        OWASP TOP 10对注入攻击的定义:注入攻击漏洞,例如SQL,OS以及LDAP注入。这些攻击发生在当不可信的数据作为命 令或者查询语句的一部分,被发送给解释器的时候。攻击者发送的恶意数据可以欺骗解释器,以执行计划外的命令或者在未被恰当授权时访问数据。首先需要确认一下,SQL注入产生的原因:第一、输入的参数可以被攻击者控制,第二,输入的参数被作为SQL语句的一部分用来组装SQL语句,此两种条件缺一不可。

        根据SQL的作用,我把SQL注入攻击分成两种类型,第一种是数据操作注入攻击, 第二种类型是查询注入攻击;。之所以分成这两种,主要还是从产生的原因和预防措施的不同来分别讲解。

第一种,数据操作注入攻击

       数据操作攻击主要是就是进行增(insert)删(delete)改(Update)操作时导致的注入攻击。在进行数据操作时,例如修改,一个典型的修改语句如下:  

update product set price=9.0 where productid='1' 

      这里的productid和price的值都是从客户端发过来的,攻击者可以通过各种拦截或者代理工具拦截对值进行修改。如果将prodcutid的值修改为:1‘ or '1'='1 ,再将price的值改为1.0,SQL语句就会变为如下:

update product set price=1.0 where productid='1' or '1'='1'

 这样就可以把所有的产品的价格修改,而且修改为更便宜的产品。

 之所以,数据操作注入攻击单独列出来,是因为它会很容易地篡改数据。不过,预防的方法也比较简单。 由于增删改数据时,一般不会使用特别复杂的条件语句,一般也不会使用模糊的条件语句,所以预防就很简单,只要把标示字符串的开始和结束的字符单引号(')转义即可。不过,不同类型的数据,转义的方法会不一样。下面表格列出几种常用的数据库和转义方法:

攻击类型危险字符编码方法例子数据库类型
SQL注入 ‘添加一个单引号转义例如:' -> ''Oracle
 ' \ 添加一个\转义例如:‘ -> \'MySQL
 '添加一个单引号转义例如:' -> ''SQL Server

        经过转义处理过的值,再组装SQL语句,就可以保证SQL语句的安全性了。 对于一些数据库,如:Oracle和MySQL,可以通过escape语句定义转义的字符,则需要使用escape语句中的字符进行转义,一般不建议这么用。       

第二种,查询注入攻击

       顾名思义,查询攻击就是输入的参数作为查询SQL语句的一部分用于查询数据。最经典的查询操作的例子,是根据输入的条件查询符合条件的记录,例如,在产品列表页面根据输入的产品名称查找所有符合产品,可能的SQL语句如下:

      精确查询

select * from product where name = '输入的值' 

     关于精确查询,注入和典型的注入类似,需要注入攻击向量:name' or '1'='1, 就可以查找到所有产品,也可以通过注入额外的SQL语句进行额外的破坏,不过这样做需要花更多的功夫和时间,即使有了SQLMAP这样的工具。

     不过,这种精确查询的预防原理和数据操作注入攻击的原理很像,只要将单引号(')进行转义处理就可以了。

    模糊查询

select * from product where name like '输入的值+%' 

    模糊查询和精确查询不同的地方就是,除了要处理单引号(')这个特殊字符之外,模糊查询有额外的特殊的字符,例如: 

字符描述
%表示零个或多个字符的任意字符串,例如:LIKE 'AA%',可以匹配AA以及AA开头的字符串。 
_表示任何单个字符,例如:LIKE'_aa',只匹配包含aa工三个字符字符串,例如:Aaa,1aa。 Oracle也可以使用?表示任何单个字符。
[ ]表示指定范围,例如: ([a-z]) 是指所有小写字母,或者 集合 [abc])中的任何单个字符,结合LIKE使用 LIKE '[Hh]ello [Ww]orld' 
*表示零个或者多个字符,和%的区别是,当需要两端都匹配时,要用%而不能用*,例如:LIKE '%aaaa%',而不能使用'*aaaa*' ,一般都用于查询内容而又不列出具体字段,例如:select * from product。
#表示单个数字,例如:LIKE ‘a#b’ 匹配  'a1b'.
{} 有的数据库使用的是大括号,作用同[]

针对这些特殊的字符的处理和单引号的处理是不同的,处理的主要方式使用一对括号将特殊字符括起来,例如:查询的字符串中含有%,假设查询字符串是a%b,就可以使用a[%]b,这样查询的内容就会含有'a%b' 而不是a开头和b结尾的所有串。不同的数据库使用不同的括号,统计如下表:

攻击类型危险字符编码方法例子数据库类型
SQL注入# % _ [ ]使用中括号[]转义例如:% -> [%]MySQL
# % _ { }使用大括号{}转义例如:% ->{%}Oracle
# % _ [ ]使用中括号[]转义例如:% -> [%]SQL Server

最后,还有一种SQL注入的地方是排序时 group by的字段的排序,一般这里都比较好处理,因为排序的字段都是数据库表的字段,都有固定的值的范围,通过输入验证是比较好的方法。当然,如果客户端传的不是字符串,而是,通过数字对应某个字段,例如:1->name,2->address等,就更容易做输入验证了,只要验证是否是数字或者数字List即可,然后,再映射成具体的字段。关于升序还是降序,那就就只有ASC或者DESC,无论怎么处理都比较方便。

总之,无论何时何地,想要把内容作为SQL的一部分,都不必须小心。即使在使用框架的时候,例如:MyBatis或者iBatis,有些情况下(使用$带入变量而不是使用#时),把输入的内容作为SQL的一部分也还是会有SQL注入。 

综上所述,可以了解SQL注入之所以发生的根本原理和最基本的预防原理。 当然,预防的方法有多种,使用编译的SQL、输入验证等,这些预防方法都有一定的缺陷不一定适用所有的情况。 如果掌握了SQL注入的最基本的原理,了解预防发生的基本原理,就可以使用这一招处理所有的SQL注入的情况。

如果有不妥之处,希望可以留言指出。谢谢!

参考:

http://www.owasp.org.cn/owasp-project/OWASPTop102017RC1V1.2.pdf

CWE - 2020 CWE Top 25 Most Dangerous Software Weaknesses

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值