1、SQL注入漏洞基本原理
在常见的web漏洞中,SQL注入漏洞较为常见,危害也较大。攻击者一旦利用系统中存在的SQL注入漏洞来发起攻击,在条件容许的状况下,不只能够获取整站数据,还可经过进一步的渗透来获取服务器权限,从而进入内网。
注入攻击的本质,是把用户输入的数据当作代码执行。这里有两个关键条件,第一个是用户可以控制输入;第二个是本来程序要执行的代码,拼接了用户输入的数据。接下来讲下SQL注入漏洞的原理。
举个栗子。
当用户发送GET请求:
http://www.xxx.com/news.jsp?id=1
这是一个新闻详情页面,会显示出新闻的title和content,程序内部会接收这个id参数传递给SQL语句,SQL以下:
SELECT title,content FROM news WHERE id = 1
这是SQL的原义,也是程序员想要获得的结果,可是若是用户改变了id的内容,修改为以下:
http://www.jd.com/news.jsp?id=1 and 1=2 UNION SELECT userna-me, password FROM admin
此时内部程序执行的SQL语句为:
SELECT title,content FROM news WHERE id = 1 and 1=2 UNION SELECT username, password FROM admin
这条SQL的原义就会被改变,致使将管理员数据表中的用户名显示在页面title位置,密码显示在页面content位置,攻击成功。
2、Mybatis框架介绍
1. Mybatis框架架构
Mybatis框架架构讲解(架构图以下图所示):
(1)加载配置:配置来源于两个地方,一处是配置文件,一处是Java代码的注解,将SQL的配置信息加载成为一个个MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存中。
(2) SQL解析:当API接口层接收到调用请求时,会接收到传入SQL的ID和传入对象(能够是Map、JavaBean或者基本数据类型),Mybatis会根据SQL的ID找到对应的MappedStatement,而后根据传入参数对象对MappedStatement进行解析,解析后能够获得最终要执行的SQL语句和参数。
(3)SQL执行:将最终获得的SQL和参数拿到数据库进行执行,获得操做数据库的结果。
(4)结果映射:将操做数据库的结果按照映射的配置进行转换,能够转换成HashMap、JavaBean或者基本数据类型,并将最终结果返回。

Mybatis架构图
2. JDBC预编译模式
Mybatis框架做为一款半自动化的持久层框架,其SQL语句都须要咱们本身手动编写,此时就须要按照安全编码规范进行开发,以防止SQL注入漏洞的产生。
针对上一节中所举的例子,应用Mybatis框架SQL语句安全写法(即JDBC预编译模式)能够写为:
select * from news where id=#{id},这种写法能够很好地避免SQL注入漏洞的产生。
3. 动态拼接SQL语句
若是在开发过程当中没有采用JDBC的预编译模式,如咱们将上述SQL语句写为:select * from news where id=${id},这种写法就产生了SQL语句的动态拼接。由于”${xxx}”这样格式的参数会直接参与SQL语句的编译,从而不能避免SQL注入攻击。
3、Mybatis框架下易产生SQL注入漏洞场景分析
在基于Mybatis框架的Java白盒代码审计工做中,一般将着手点定位在Mybatis的配置文件中。经过查看这些与数据库交互的配置文件来肯定SQL语句中是否存在拼接状况,进而确立跟踪点。经过总结,Mybatis框架下易产生SQL注入漏洞的状况主要分为如下三种:
1. 模糊查询like
还以第一节中提到的新闻详情页面为例,按照新闻标题对新闻进行模糊查询,若是考虑安全编码规范问题,其对应的SQL语句以下:
Select * from news where title like ‘%#{title}%’,
但因为这样写程序会报错,研发人员将SQL查询语句修改以下:
Select * from news where title like ‘%${title}%’,
在这种状况下咱们发现程序再也不报错,可是此时产生了SQL语句拼接问题,若是java代码层面没有对用户输入的内容作处理势必会产生SQL注入漏洞。
2. in以后的参数
在对新闻进行同条件多值查询的时候,如当用户输入1001,1002,1003…100N时,若是考虑安全编码规范问题,其对应的SQL语句以下:
Select * from news where id in (#{id}),
但因为这样写程序会报错,研发人员将SQL查询语句修改以下:
Select * from news where id in (${id}),
修改SQL语句以后,程序中止报错,可是却引入了SQL语句拼接的问题,若是研发人员没有对用户输入的内容作过滤,势必会产生SQL注入漏洞。
3. order by以后
当根据发布时间、点击量等信息对新闻进行排序的时候,若是考虑安全编码规范问题,其对应的SQL语句以下:
Select * from news where title =‘京东’ order by #{time} asc,
但因为发布时间time不是用户输入的参数,没法使用预编译。研发人员将SQL查询语句修改以下:
Select * from news where title =‘京东’ order by ${time} asc,
修改以后,程序经过预编译,可是产生了SQL语句拼接问题,极有可能引起SQL注入漏洞。
4、Mybatis框架下SQL注入漏洞修复建议1. 模糊查询like SQL注入修复建议
按照新闻标题对新闻进行模糊查询,可将SQL查询语句设计以下:
select * from news where tile like concat(‘%’,#{title}, ‘%’),
采用预编译机制,避免了SQL语句拼接的问题,从根源上防止了SQL注入漏洞的产生。
2. in以后的参数SQL注入修复建议
在对新闻进行同条件多值查询的时候,可以使用Mybatis自带循环指令解决SQL语句动态拼接的问题:
<select id="dynamicForeachTest" parameterType="java.util.List" resultType="Blog">
select * from t_blog where id in
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
3. order by SQL注入修复建议--在Java层面作映射
预编译机制只能处理查询参数,其余地方还须要研发人员根据具体状况来解决。如前面提到的排序情景: Select * from news where title =‘京东’ order by #{time} asc,这里time不是查询参数,没法使用预编译机制,只能这样拼接:Select * from news where title =‘京东’ order by ${time} asc 。
针对这种状况研发人员能够在java层面作映射来进行解决。如当存在发布时间time和点击量click两种排序选择时,咱们能够限制用户只能输入1和2。当用户输入1时,咱们在代码层面将其映射为time,当用户输入2时,将其映射为click。而当用户输入1和2以外的其余内容时,咱们能够将其转换为默认排序选择time(或者click)。