mybatis如何预防不经意间的SQL注入 1. 理论 2. 实践 文章参考

SQL注入的危害就不多说,但是如何在日常开发中预防SQL注入?

1. 理论

  1. 什么是SQL注入

注入攻击的本质,是程序把用户输入的数据当做代码执行。这里有两个关键条件:
第一是用户能够控制输入;
第二是用户输入的数据被拼接到要执行的代码中从而被执行。

sql注入漏洞则是程序将用户输入数据拼接到了sql语句中,从而攻击者即可构造、改变sql语义从而进行攻击。

  1. SQL漏洞一般的预防措施:
  1. 对于接受外部参数的动态SQL,能够进行预编译操作的地方一律使用预编译,禁止直接从字符串拼接SQL;
  2. 对于SQL不能预编译的地方,例如order by $param处,应该使用严格的白名单进行校验,然后拼接参数;
  1. mybatis动态sql的两种方式

动态 sql 是 mybatis 的主要特性之一,在mybatis中我们可以把参数传到xml文件,由mybatis对sql及其语法进行解析,mybatis支持使用${}和#{}。

#{}:在mybatis中是预编译操作;
${}:在mybatis中是直接拼接;

  1. 为什么#{}可以预发SQL注入

直观的理由:

使用${}方式传入的参数,mybatis不会对它进行特殊处理,而使用#{}传进来的参数,mybatis默认会将其当成字符串。

例如:selec * from #{table};
解析后:select * from "test";

例如:selec * from ${table};
解析后:select * from test;

因为前者多了字符串的引号,那么可以预防sql注入。

书面化的理由是:

#和$在预编译处理中是不一样的。#类似jdbc中的PreparedStatement,对于传入的参数,在预处理阶段会使用?代替,待真正查询的时候,即在数据库管理系统中(DBMS)才会代入参数。而${}只是简单的替换。

2. 实践

2.1 一般sql的处理

核心:能够进行预编译的地方,一律使用#{}进行预编译。

在where接受参数:

    <select id="selectField">
        SELECT field_name FROM table_name WHERE 1 = 1
        <if test="condition != null">
            AND field_name = #{condtion} <!--禁止使用${param}拼接-->
        </if>
    </select>

在like接受参数:使用CONCAT函数。

    <select id="selectByLike">
        SELECT field_name FROM table_name WHERE 1 = 1
        <if test="condition != null">
            AND field_name like CONCAT(#{condition}, '%') <!--禁止使${param}拼接-->
        </if>
    </select>

在in处接受参数:

    <select id="selectInSQL">
        SELECT field_name FROM table_name WHERE 1 = 1
        <if test="conditionArray != null">
            field_name in
            <!--禁止使用${param}拼接-->
            <foreach collection="conditionArray" item="item"  open="(" close=")" separator=",">
                #{item}
            </foreach>
        </if>
    </select>

2.2 order by的处理

核心:不能使用#{}进行预编译时,在mybatis进行白名单校验。

    <select id="sortSQL">
        SELECT field_name FROM table_name WHERE 1 = 1
        <!--传入的字段不为空,且传入的字段为name,才执行`order by name`的sql-->
        <if test="columnName != null and columnName=='name'.toString()"> 
            order by name
            <if test="orderName !=null and orderName=='desc'.toString()">
                desc
            </if>
            <if test="orderName !=null and orderName=='asc'.toString()">
                asc
            </if>
        </if>
    </select>

文章参考

mybatis中的#和$的区别

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章