Mybatis動態指定表名、列名,如何防止SQL注入?
阿新 • • 發佈:2020-11-06
以下的程式碼,操作的是MySQL資料庫
方式一
因為表名無法通過 CONCAT() 函式進行拼接,所以只能通過 ${} 直接將表名的字串替換。
<select id="selectUnionALL" resultType="Dept"> SELECT * FROM ${tableName} WHERE deptno = #{deptno} </select>
但是會存在SQL的注入,比如:tableName = dept_01; delete from dept_01; 就會刪除所有的資料。
解決方式:通過程式碼去判斷傳入的引數是否包含 delete、drop... 等危險操作。
方式二
可以通過儲存過程去解決動態指定表名的問題。
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 $$ 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>