Mybatlis SQL 注入与防范
SQL注射原理
所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。
攻击方式
猜表名
And (Select count(*) from 表名)<>0
and exists (select * from 表名)
猜列名
And (Select count(列名) from 表名)<>0
and exists (select 列名 from 表名)
拉全表
' or 1 = 1 #
#可以注释掉后面的一行SQL代码
实战演练
正常请求
http://xxxxxx/sc?cn=sc
响应结果数量:

注入请求
http://xxxxxx/sc?cn=sc' or 1= 1 or '' = '
响应结果数量:

可以从响应结果数中看到,它已经几乎把我们所有的数据给拉了出来。
防御调整
原查询语句
<!--查询学校--><select id="selectSchool" resultMap="BaseResultMap" parameterType="map"> select xxx from yyyy where zzz = 'section' and deleted_at is null and is_open = 1 <if test="name !=null"> and name like '%${name}%' </if> <if test="pinyin !=null"> and pinyin_initial like '${pinyin}%' </if> order by id</select> |
调整后语句
<!--查询学校--><select id="selectSchool" resultMap="BaseResultMap" parameterType="map"> select xxx from yyyy where zzz = 'section' and deleted_at is null and is_open = 1 <if test="name !=null"> and name like concat(concat('%',#{name}),'%') </if> <if test="pinyin !=null"> and pinyin_initial like concat((#{pinyin}),'%') </if> order by id</select> |
调整后执行日志
2016-03-11 16:06:29.661 [http-nio-8080-exec-8] DEBUG org.mybatis.spring.SqlSessionUtils 106 getSqlSession- Creating a new SqlSession2016-03-11 16:06:29.663 [http-nio-8080-exec-8] DEBUG org.mybatis.spring.SqlSessionUtils 142 getSqlSession- SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@647a5210] was not registered for synchronization because synchronization is not active2016-03-11 16:06:29.677 [http-nio-8080-exec-8] DEBUG o.m.spring.transaction.SpringManagedTransaction 85 openConnection- JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@69787b57] will not be managed by Spring2016-03-11 16:06:29.678 [http-nio-8080-exec-8] DEBUG c.z.customer.base.dao.DistrictMapper.selectSchool 132 debug- ooo Using Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@69787b57]2016-03-11 16:06:29.678 [kafka-producer-network-thread | producer-2] DEBUG org.apache.kafka.clients.NetworkClient 385 maybeUpdateMetadata- Trying to send metadata request to node -12016-03-11 16:06:29.679 [http-nio-8080-exec-8] DEBUG c.z.customer.base.dao.DistrictMapper.selectSchool 132 debug- ==> Preparing: select id ,name ,parent_id,district_type,pinyin,pinyin_initial from districts where district_type = 'section' and deleted_at is null and is_open = 1 and name like concat(concat('%',?),'%') order by id2016-03-11 16:06:29.682 [http-nio-8080-exec-8] DEBUG c.z.customer.base.dao.DistrictMapper.selectSchool 132 debug- ==> Parameters: sh' or 1 =1 or '' = '(String)2016-03-11 16:06:29.705 [http-nio-8080-exec-8] DEBUG org.mybatis.spring.SqlSessionUtils 170 closeSqlSession- Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@647a5210] |
调整后响应数据为空
{ "success": true, "data": { "schools": [] }}#号与$区别
#号表示参数,$代表一个字符串。
select a,b,c from table1 where id=#value# 传入参数后如:value="1",则可生成:select a,b,c from table1 where id=‘1’。 select a,b,c from table1 where city like '%$value$%' 传入参数后:value="berg",则可生成:select a,b,c from table1 where city like '%berg%'。${} 为原样输出,你传什么,sql里就填入什么。比如有引号它也会原样填到sql里。#{} 会使用 PreparedStatement,变量处用 ? 代替。 在能使用 #{} 尽量使用它吧,可以防止sql注入。在用#时,会在数据库里面生成一颗执行树,每一个参数就像是填空题一样被放入这颗执行树中。每次SQL执行时,执行树都是生成好的,不用重复解析SQL。同时也提升了SQL执行效率。
浮生潦草闲愁广,一听啤酒一口尽
浙公网安备 33010602011771号