Mybatis動態指定表名、列名,如何防止SQL注入?


以下的代碼,操作的是MySQL數據庫

方式一

因為表名無法通過 CONCAT() 函數進行拼接,所以只能通過 ${} 直接將表名的字符串替換。

<select id="selectUnionALL" resultType="Dept">
    SELECT * FROM ${tableName} WHERE deptno = #{deptno}
</select>

但是會存在SQL的注入,比如:tableName = dept_01; delete from dept_01; 就會刪除所有的數據。

解決方式:通過代碼去判斷傳入的參數是否包含 delete、drop... 等危險操作。

方式二

假設存在數據庫中存在 dept_01,dept_02,dept_03..... 這樣命名的表,那么怎么做呢?

可以通過存儲過程去解決動態指定表名的問題。

1)創建存儲過程

DROP PROCEDURE IF EXISTS getName;    -- 如果一創建存儲過程則刪除
DELIMITER $$ -- 定義結束字符,可以任意
-- 創建名稱為getName的存儲過程,需要傳入的參數:tableName表名,deptno條件
CREATE PROCEDURE getName(IN tableName VARCHAR(100), IN deptno INT)
BEGIN
    DECLARE tn VARCHAR(10);    -- 創建變量保存表名
    set tn = 
    (    -- 查詢MySQL中所有的表,然后根據 表所在的數據庫 和 表的后綴名稱 獲取到對應的表名
        select table_name     
        from information_schema.TABLES 
        where table_schema='db03' 
                    AND table_name LIKE CONCAT('dept_', '%')
                    AND table_name LIKE CONCAT('%', tableName)
    );
    -- 再拼接查詢語句
    set @sqlStr = CONCAT("SELECT * FROM ", tn," WHERE deptno = '", deptno, "'");
    PREPARE sqlStr FROM @sqlStr;    
    EXECUTE sqlStr;    -- 執行
END $$
-- 傳入參數:表名的后綴  部門id
CALL getName('02', 5);    -- 測試

測試結果,這樣就不存在注入問題,因為表名被作為了條件。

2)接口編寫

// Controller層
@GetMapping("selectUnionALL/db03")
@ResponseBody
public List<Dept> selectUnionALL() {
    Dept dept = new Dept();
    dept.setDeptno(5L);
    dept.setTableName("02");

    return deptService.selectUnionALL(dept);
}
// service層
public List<Dept> selectUnionALL(Dept dept) {
    return deptMapper.selectUnionALL(dept);
}
// mapper層
List<Dept> selectUnionALL(Dept dept);

3)mapper.xml 調用

<!-- statementType: 需要設置為 CALLABLE -->
<select id="selectUnionALL" resultType="Dept" statementType="CALLABLE">
    CALL getName(#{tableName}, #{deptno});
</select>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM