1. 程式人生 > >MyBatis排序時使用order by 動態引數時需要注意,用$而不是#, #{}和${}的區別以及order by注入問題

MyBatis排序時使用order by 動態引數時需要注意,用$而不是#, #{}和${}的區別以及order by注入問題

ORDER BY ${columnName}
這裡MyBatis不會修改或轉義字串

重要:接受從使用者輸出的內容並提供給語句中不變的字串,這樣做是不安全的。這會導致潛在的SQL注入攻擊,因此你不應該允許使用者輸入這些欄位,或者通常自行轉義並檢查。

#{}相當於jdbc中的preparedstatement

${}是輸出變數的值

簡單的說就是#{}傳過來的引數帶單引號'',而${}傳過來的引數不帶單引號。

你可能說不明所以,不要緊我們看2段程式碼:

String sql = "select * from admin_domain_location order by ?";
PreparedStatement st = con.prepareStatement(sql);
st.setString(1, "domain_id");
System.out.println(st.toString());

ResultSet rs = st.executeQuery();

while(rs.next()){

System.out.println(rs.getString("domain_id"));

}

輸出結果:

[email protected]: select * from admin_domain_location order by 'domain_id'

3

4

5

2

6

這是個jdbc的preparedstatement例子,不要吐槽我這麼寫是否合法,這裡只是為了說明問題.

以上例子有得出以下資訊: 1) order by後面如果採用預編譯的形式動態輸入引數,那麼實際插入的引數是一個字串,例子中是:order by  'domain_id'

2)輸出結果並沒有排序,從sql語句中的形式我們也可以推測出此sql語句根本也不合法(正常應該是 order by domain_id )

修改以上程式碼如下:

String input = "domain_id";
String sql = "select * from admin_domain_location order by "+input;
PreparedStatement st = con.prepareStatement(sql);
System.out.println(st.toString());
ResultSet rs = st.executeQuery();
while(rs.next()){
    System.out.println(rs.getString("domain_id"));
}
輸出結果:

[email protected]: select * from admin_domain_location order by domain_id

2

3

4

5

6

此次我們直接把一個變數的值拼接sql語句,從結果可以看出來:

1)sql語句拼接正常

2)查詢結果排序正常

你可能要問這和#{}與${}有什麼關係..

上面已經說過#{}相當於jdbc的preparedstatement,所以以上的第一個例子就相當於#{},那麼第二個例子就自然而然指的是${}的情況.

你可能說思維還是有些凌亂,不要緊我們來看第三個例子:

String sql = "select * from admin_domain_location where domain_id=?";
PreparedStatement st = con.prepareStatement(sql);
st.setString(1, "2");
System.out.println(st.toString());
ResultSet rs = st.executeQuery();
while(rs.next()){
  System.out.println(rs.getString("domain_id"));
}
=======================================
String input = "2";
String sql = "select * from admin_domain_location where domain_id='"+input+"'";
PreparedStatement st = con.prepareStatement(sql);
System.out.println(st.toString());
ResultSet rs = st.executeQuery();
while(rs.next()){
  System.out.println(rs.getString("domain_id"));
}
輸出結果都為:
[email protected]12bf560: select * from admin_domain_location where domain_id='2'
2

這第三個例子雖然說的是#{}和{}通用的問題,也就是說在此種情況下#{}和{}通用的問題,也就是說在此種情況下#{}和{}是通用的,只不過需要些小的轉換.如例子中需要手動

拼接單引號 ' ' 到變數值的前後,確保sql語句正常.

簡單說#{}是經過預編譯的,是安全的,而${}是未經過預編譯的,僅僅是取變數的值,是非安全的,存在sql注入.

這裡先說一下只能,,orderby的情況,從我們前面的例子中也能看出,orderby是肯定只能用{}了,用#{}會多個' '導致sql語句失效.此外還有一個like 語句後也需要用${},簡單想一下

就能明白.由於,sql,orderby僅僅是簡單的取值,所以以前sql注入的方法適用此處,如果我們orderby語句後用了{},那麼不做任何處理的時候是存在sql注入危險的.你說怎麼防止,那我只

能悲慘的告訴你,你得手動處理過濾一下輸入的內容,如判斷一下輸入的引數的長度是否正常(注入語句一般很長),更精確寫查詢一下輸入的引數是否在預期的引數集合中..

原文:http://www.cnblogs.com/yanspecial/p/5659429.html