Mybatis框架下的SQL注入常见问题与修复

一、知识点:

  MyBatis支持两种参数符号,一种是#,另一种是$。
  在sql语句中使用like、in、order by时,程序员易使用不当直接sql语句拼接,造成SQL注入。

  • 使用参数符号#时
<select id="selectPerson" parameterType="int" resultType="hashmap">
SELECT * FROM PERSON WHERE ID = #{id}
</select>

  MyBatis会创建一个预编译语句,生成的代码类似于

// Similar JDBC code, NOT MyBatis…
String selectPerson = "SELECT * FROM PERSON WHERE ID=?";
PreparedStatement ps = conn.prepareStatement(selectPerson);
ps.setInt(1,id);

  参数会在SQL语句中用占位符”?”来标识,然后使用prepareStatement来预编译这个SQL语句,而用户提交的数据,只作为参数,不会被带入sql进行编译,从而防止了SQL注入漏洞的产生。

  • 使用参数符号$时:

  MyBatis直接用字符串拼接把参数和SQL语句拼接在一起,然后执行,这种情况非常危险,极容易产生SQL注入漏洞。

二、易产生SQL注入漏洞的情况

主要分为以下三种:

  • 模糊查询like

  以按照标题进行模糊查询为例,如果考虑安全编码规范问题,其对应的SQL语句如下:

select * from news where title like '%#{title}%'

  但由于这样写程序会报错,所以一般将SQL查询语句修改如下:

select * from news where title like '%${title}%'

  在这种情况下程序不再报错,但是此时产生了SQL语句拼接问题,如果java代码层面没有对用户输入的内容做处理势必会产生SQL注入漏洞。

修复建议

  可将SQL查询语句修改如下:

select * from news where tile like concat('%',#{title}, '%')

采用预编译机制,避免了SQL语句拼接的问题,从根源上防止了SQL注入漏洞的产生。

  • in之后的参数

  在进行同条件多值查询的时候,如当用户输入1001,1002,1003…100N时,如果考虑安全编码规范问题,其对应的SQL语句如下:

select * from news where id in (#{id})

  但由于这样写程序会报错,研发人员将SQL查询语句修改如下:

select * from news where id in (${id})

  修改SQL语句之后,程序停止报错,但是却引入了SQL语句拼接的问题,如果没有对用户输入的内容做过滤,势必会产生SQL注入漏洞。

修复建议

  在对进行同条件多值查询的时候,可使用Mybatis自带循环指令解决SQL语句动态拼接的问题:

select * from news where id in
<foreach collection='ids' item='item' open='(' separator=',' close=')'>
#{item}
</foreach>
  • order by之后

  当根据发布时间、点击量等信息进行排序的时候,如果考虑安全编码规范问题,其对应的SQL语句如下:

select * from news where title =‘test’ order by #{time} asc

  但由于这样写程序会报错,将SQL查询语句修改如下:

select * from news where title =‘test’ order by ${time} asc

  修改之后,程序可以正常查询,但是产生了SQL语句拼接问题,可能引发SQL注入漏洞。

修复建议

  针对这种情况可以在java层面做映射来进行解决。
  如当存在发布时间time和点击量click两种排序选择时,可以限制用户只能输入1和2。当用户输入1时,在代码层面将其映射为time,当用户输入2时,将其映射为click。而当用户输入1和2之外的其他内容时,可以将其转换为默认排序选择time(或者click)。

参考

MyBatis框架中常见的SQL注入
简单说说MySQL Prepared Statement
Mybatis框架下SQL注入漏洞面面观
SQL注入的“冷门姿势”
MyBatis与SQL注入
myBatis的SQL注入问题

点赞

发表评论

电子邮件地址不会被公开。必填项已用 * 标注