mybatis如何防止SQL注入?
一、采用jdbc操作數(shù)據(jù)時(shí)候
- String sql = "update ft_proposal set id = "+id;
- PreparedStatement prepareStatement = conn.prepareStatement(sql);
- prepareStatement.executeUpdate();
preparedStatement 預(yù)編譯對(duì)象會(huì)對(duì)傳入sql進(jìn)行預(yù)編譯,那么當(dāng)傳入id 字符串為 "update ft_proposal set id = 3;drop table ft_proposal;" 這種情況下就會(huì)導(dǎo)致sql注入刪除ft_proposal這張表。
如何防止sql注入,首先將要執(zhí)行sql進(jìn)行預(yù)編譯,然后在將占位符進(jìn)行替換
- String sql = "update ft_proposal set id = ?"
- PreparedStatement ps = conn.preparedStatement(sql);
- ps.setString(1,"2");
- ps.executeUpdate();
處理使用預(yù)編譯語(yǔ)句之外,另一種實(shí)現(xiàn)方式可以采用存儲(chǔ)過(guò)程,存儲(chǔ)過(guò)程其實(shí)也是預(yù)編譯的,存儲(chǔ)過(guò)程是sql語(yǔ)句的集合,將所有預(yù)編譯的sql 語(yǔ)句編譯完成后,存儲(chǔ)在數(shù)據(jù)庫(kù)上,
由于存儲(chǔ)過(guò)程比較死板一般不采用這種方式進(jìn)行處理。
二、mybatis是如何處理sql注入的?
假設(shè)mapper.xml文件中sql查詢(xún)語(yǔ)句為:
- <select id="findById" resultType="String">
- select name from user where id = #{userid};
- </select>
對(duì)應(yīng)的接口為:
- public String findById(@param("userId")String userId);
當(dāng)傳入的參數(shù)為3;drop table user; 當(dāng)我們執(zhí)行時(shí)可以看見(jiàn)打印的sql語(yǔ)句為:
select name from usre where id = ?;
不管輸入何種參數(shù)時(shí),都可以防止sql注入,因?yàn)閙ybatis底層實(shí)現(xiàn)了預(yù)編譯,底層通過(guò)prepareStatement預(yù)編譯實(shí)現(xiàn)類(lèi)對(duì)當(dāng)前傳入的sql進(jìn)行了預(yù)編譯,這樣就可以防止sql注入了。
如果將查詢(xún)語(yǔ)句改寫(xiě)為:
- <select id="findById" resultType = "String">
- select name from user where id=${userid}
- </select>
當(dāng)輸入?yún)?shù)為3;drop table user; 執(zhí)行sql語(yǔ)句為
- select name from user where id = 3;drop table user ;
mybatis沒(méi)有進(jìn)行預(yù)編譯語(yǔ)句,它先進(jìn)行了字符串拼接,然后進(jìn)行了預(yù)編譯。這個(gè)過(guò)程就是sql注入生效的過(guò)程。
因此在編寫(xiě)mybatis的映射語(yǔ)句時(shí),盡量采用“#{xxx}”這樣的格式。若不得不使用“${xxx}”這樣的參數(shù),要手工地做好過(guò)濾工作,來(lái)防止sql注入攻擊。