技术干货 | 简析Sql注入与防御措施

Posted 安全加

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了技术干货 | 简析Sql注入与防御措施相关的知识,希望对你有一定的参考价值。


首先,什么是Sql注入呢?英文名称为SqlInject,把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令(度娘说的)。

概念说的再好不如去实践一下,接下来咱们就看看什么是Sql注入,Sql注入的方式有哪些?

(下面使用的是JavaWeb技术,不过不影响大家看,因为和平台关系不大)

 一.sql注入方式

我们日常访问的路径,如:http://www.example.com/,这个是一个正常的页面请求语句,没有涉及到任何动态请求数据库的动作,所以这种情况下是不会有SQL注入的。像http://www.example.com?userid=1这个URL请求,其中包含了一个Key-Value对(学过Web的这里就不多费口舌了),那么我们通过这个URL语句可以向数据库发送userid的数据,从而进行“增删改查”。也就是说"?"后面的数据是和数据库打交道的,那么在"?"后面跟的信息就有可能会被加入恶意的SQL语句。

我们做测试的数据库为mysql,数据库名为user,表名users,其中的字段如下:

技术干货 | 简析Sql注入与防御措施

我储存了一些测试数据,如下:

技术干货 | 简析Sql注入与防御措施

我们有一个根据ID来查询用户信息的Dao层方法(这里id用String是为了模拟涵盖类似UUID那种类型的id),

技术干货 | 简析Sql注入与防御措施

然后是执行这个Dao层方法并返回信息给网页的Servlet:

技术干货 | 简析Sql注入与防御措施

之后我们访问这个路径,我们就得到了userid=2的用户的数据

技术干货 | 简析Sql注入与防御措施

很显然,我们的SQL语句是:

技术干货 | 简析Sql注入与防御措施

如果我们在where这里加上一句“ or 1=1”,这样的话,where条件就变为永真(where (userid=#{id} or 1=1)),这个时候我们的sql语句就会变为:

技术干货 | 简析Sql注入与防御措施

那么我们就会把所有的users表中的数据都取出来。

所以,当我们输入这样的URL:http://localhost/SqlInjectTest/GetUser?userid=2 or 1=1

这个时候我们的SQL语句就变成了这样:

技术干货 | 简析Sql注入与防御措施

然后很明显,我们的where已经失效了,这个时候我们取出的结果是什么样子呢?


结果是:

技术干货 | 简析Sql注入与防御措施

得到的不是id为2的用户,而是id为1的用户!!!

为什么?因为我们是取出所有的用户,但是我们在Dao方法中只接受了一个结果集,并把这个结果集封装给一个User对象带到最终的网页上去,所以我们这里只得到所有数据的第一条。


虽然刚刚不是什么惊天大Bug,但是足以让网站乱了套。如果你使用了SpringMVC框架,接收的参数是一个字符串类型(Serializable[] ids),反馈的结果的是List<User>集合,那么恭喜你,黑客会黑出你所有的用户信息:

技术干货 | 简析Sql注入与防御措施

通过一个简单的sql注入获取一些简单的信息,获取user用户信息并没有太大的价值,那么如果我们知道user信息的表名,是不是就可以利用它进行“增删查修”了?没有错,确实可以做到,但是前提是我们需要知道这个网站的数据库表名是什么。


我们可以对它来进行推测,使用试错法,试验几次。我们先来试验它是什么类型的数据库,我们先推测一个数据库的表名,然后写一个sql语句,看看它会会不会有错,然后通过不断尝试来获取数据库真实的表名。

这里面我们假设表的名字就叫user,我们访问这么一个URL:

http://localhost/SqlInjectTest/GetUser?userid=2 or 1=(select count(*) from user)

访问后的界面如下:

技术干货 | 简析Sql注入与防御措施

我们前面的数据没有查出来,说明数据库在解析sql语句的时候出了错,最终没有输出数据(有些后台还会报错,通过错误前缀代码还可以推测是什么数据库)。说明我们推测的表名是错误的。

假设这个网站的设计者很随意,他设计的表名很简单,就是users。那么,当我们利用暴力测试之后知道它的表名是users的时候,我在URL路径后面注入各种“增删改查”的sql语句,那就会十分的危险。

● 二.防止sql注入的几种方法 

(1)PreparedStatement

始终以PreparedStatement代替Statement

采用JDBC的预编译语句集,它内置了处理SQL注入的能力,只要使用它的setXXX方法传值即可。

使用好处:

(1).代码的可读性和可维护性.

(2).PreparedStatement尽最大可能提高性能.

(3).最重要的一点是极大地提高了安全性.

原理:

sql注入只对sql语句的准备(编译)过程有破坏作用

而PreparedStatement已经准备好了,执行阶段只是把输入串作为数据处理,

而不再对sql语句进行解析,准备,因此也就避免了sql注入问题.

PreparedStatement需要服务器端的支持来提高效率。比如在Oracle上就会有显著效果,而MySQL上select时不支持PreparedStatement(亲测)。


(2)过滤sql语句保留字

使用正则表达式来过滤一些sql关键字,如or、where等

技术干货 | 简析Sql注入与防御措施

同时也可以通过这种方式来使用关键字检查sql是否有注入:

技术干货 | 简析Sql注入与防御措施

(3)正则表达式检查sql

大致方法:

技术干货 | 简析Sql注入与防御措施

具体的正则表达式:

检测SQL meta-characters的正则表达式 :/(\%27)|(’)|(--)|(\%23)|(#)/ix

修正检测SQL meta-characters的正则表达式 :/((\%3D)|(=))[^ ]*((\%27)|(’)|(--)|(\%3B)|(:))/i

典型的SQL 注入攻击的正则表达式 :/w*((\%27)|(’))((\%6F)|o|(\%4F))((\%72)|r|(\%52))/ix

检测SQL注入,UNION查询关键字的正则表达式 :/((\%27)|(’))union/ix(\%27)|(’)

检测MS SQL Server SQL注入攻击的正则表达式:/exec(s|+)+(s|x)pw+/ix

等等…..


(4)其它

还有其它的方式,只要保证传入的参数仅仅是数值而包含sql关键字等信息,或者在执行sql前将参数格式化等等措施,都可以防止sql注入。


原文链接:

https://blog.csdn.net/acmman/article/details/48862841

技术干货 | 简析Sql注入与防御措施

以上是关于技术干货 | 简析Sql注入与防御措施的主要内容,如果未能解决你的问题,请参考以下文章

技术干货 | CSRF攻击原理以及防御

什么是SQL注入式攻击 如何防范

asp.net 怎么防止SQL注入攻击啊???

电子书 SQL注入攻击与防御.pdf

针对sql注入攻击,都有哪些防范措施

web攻击与防御技术--SQL注入