在一次修改動態(tài)拼接的表名的sql時(shí),使用#{},一直報(bào)錯,檢查sql沒有問題,最終發(fā)現(xiàn),在<select>標(biāo)簽中有這么一個(gè)屬性statementType="STATEMENT";
statementType="STATEMENT" ,這個(gè)屬性是不開啟預(yù)編譯,#{}是使用預(yù)編譯的,導(dǎo)致,sql中的占位符?一直沒有被傳入的參數(shù)所替換掉,所有一直沒有找到傳入的參數(shù)。
之前很多動態(tài)拼接表名或者字段名的,都是采用這個(gè),然后入?yún)⒈仨毴渴?{}才不會報(bào)錯,但是現(xiàn)在可以不用寫這個(gè)屬性了,默認(rèn)的開啟預(yù)處理,也能使用${}。
${} 和 #{}是可以并存的
但是有一點(diǎn)要注意的是,使用${}的時(shí)候要注意防止sql注入的問題了
如何防止sql注入?
1.使用#{}一勞永逸,但是特殊的地方,像是表名,字段名就要是'${}'
【底層實(shí)現(xiàn)原理】MyBatis是如何做到SQL預(yù)編譯的呢?其實(shí)在框架底層,是JDBC中的PreparedStatement類在起作用,PreparedStatement是我們很熟悉的Statement的子類,它的對象包含了編譯好的SQL語句。這種“準(zhǔn)備好”的方式不僅能提高安全性,而且在多次執(zhí)行同一個(gè)SQL時(shí),能夠提高效率。原因是SQL已編譯好,再次執(zhí)行時(shí)無需再編譯。
2.使用正則表達(dá)式過濾傳入的參數(shù)
要引入的包:
import java.util.regex.*;
正則表達(dá)式:
private String CHECKSQL = “^(.+)\\sand\\s(.+)|(.+)\\sor(.+)\\s$”;
判斷是否匹配:
Pattern.matches(CHECKSQL,targerStr);
下面是具體的正則表達(dá)式:
檢測SQL meta-characters的正則表達(dá)式 :
/(\%27)|(\’)|(\-\-)|(\%23)|(#)/ix
修正檢測SQL meta-characters的正則表達(dá)式 :/((\%3D)|(=))[^\n]*((\%27)|(\’)|(\-\-)|(\%3B)|(:))/i
典型的SQL 注入攻擊的正則表達(dá)式 :/\w*((\%27)|(\’))((\%6F)|o|(\%4F))((\%72)|r|(\%52))/ix
檢測SQL注入,UNION查詢關(guān)鍵字的正則表達(dá)式 :/((\%27)|(\’))union/ix(\%27)|(\’)
檢測MS SQL Server SQL注入攻擊的正則表達(dá)式:
/exec(\s|\+)+(s|x)p\w+/ix
等等…..
3.字符串過濾
比較通用的一個(gè)方法:
(||之間的參數(shù)可以根據(jù)自己程序的需要添加)
public static boolean sql_inj(String str){
String inj_str = "'|and|exec|insert|select|delete|update|
count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+|,";
String inj_stra[] = split(inj_str,"|");
for (int i=0 ; i < inj_stra.length ; i++ ){
if (str.indexOf(inj_stra[i])>=0){
return true;
}
}
return false;
}