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中的#和$的區別

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