Mybatis中会引起sql注入风险的问题

该风险漏洞是我驻场的公司(ciccwm)在一次安全漏洞检查中提出,我在此作为引用,特此声明。

风险说明

SQL 注入 (SQLi) 是一种注入攻击,可以执行恶意 SQL 语句。这些语句控制 Web 应用程序后面的数据库服务器。攻击者可以利用 SQL 注入漏洞绕过应用程序安全措施。他们可以绕过网页或 Web 应用程序的身份验证和授权,并检索整个 SQL 数据库的内容。他们还可以使用 SQL 注入来添加、修改和删除数据库中的记录。

在 SQL 注入攻击中,用户可以直接向数据库提交 SQL 查询,无需提供适当的凭据即可获得访问权限。然后攻击者可以查看、导出、修改和删除机密信息;更改密码和其他身份验证信息;并可能访问网络中的其他系统。这是最常被利用的漏洞类别之一,但可以通过良好的编码实践在很大程度上避免。

变量名称周围的 #字符表示 iBatis 将使用 userName变量创建参数化查询。但是,iBatis 还允许使用 $字符将变量直接连接到 SQL 指令,使其易受 SQL injection 攻击。

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注入漏洞。

解决方案

主要解决方案参考如下:
1)避免将用户输入的参数直接传递给 SQL 服务器。
2)编码时,先定义SQL代码,再传入参数。将准备好的语句与参数化查询一起使用。
3)对所有参数使用强类型,以便拒绝意外的用户数据。
4)如果出于性能原因无法避免直接用户输入,请根据非常严格的允许字符列表验证输入,避免使用特殊字符,例如? & / < > ; -和空格。如果可能,建议使用供应商提供的转义例程。
5)使用可防止 SQL 注入的库。
6)围绕最小权限模型​​强化整个环境,理想情况下使用仅具有特定任务权限的隔离帐户。
7)MyBatis Mapper配置文件中的SQL语句中存在用户输入的字符串,且使用$字符将变量直接连接到SQL指令,而未使用安全的符号“#”进行参数化查询。

参考代码示例:
使用带“#”占位符的预编译执行方式的SQL语句,并且,所有非程序自身的数据都不参与SQL语句的构成。

<select id="getItems" parameterType="domain.company.MyParamClass" resultType ="MyResultMap">
	SELECT * FROM items
	WHERE owner = #{userName}
	AND itemname = #{itemName}
</select>

针对like、in和order by三种注入场景,参考解决方案如下:
(1)模糊查询like SQL注入修复建议
按照标题进行模糊查询,可将SQL查询语句设计如下:

select* fromnews wheretile likeconcat(%,#{title}, ‘%’),
采用预编译机制,避免了SQL语句拼接的问题,从根源上防止了SQL注入漏洞的产生。

(2)in之后的参数SQL注入修复建议
在进行同条件多值查询的时候,可使用Mybatis自带循环指令解决SQL语句动态拼接的问题:

 <update id="updateRzrqState" parameterType="map">
    update web_rzrq_article set state= #{state},quit_time=NOW()
    where id  in
    <foreach item="id" collection="ids" open="(" close=")" separator=",">
      #{id}
    </foreach>
  </update>

(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)。

猜你喜欢

转载自blog.csdn.net/flytalei/article/details/131164743