關於mybatis使用${}時sql註入的問題
mybatis使用${}時sql註入的問題
最近在上線項目的時候,代碼審查沒有通過,提示有sql註入的風險。
ORDER BY ${orderBy}
很簡單的一個排序字段,但是因為使用 ${} 占位符的原因,有sql註入的風險,相信大傢平時也經常會使用這個占位符,不知道有沒有考慮sql註入的問題,下面簡單介紹下 #{} 和 ${} 的區別以及為什麼使用 ${} 會有sql註入的問題。
區別
- #{}是一個參數占位符,對於String類型會自動加上””,其他類型不加。由於Mybatis采用預編譯,其後的參數不會再進行SQL編譯,所以一定程度上防止SQL註入。
- ${}是一個簡單的String替換,字符串是什麼,解析就是什麼。
- 類如order by。假如前端傳的參數是id(假設id是String類型),對於order by #{id},對應的sql語句就是 order by “id”;對於order by ${id},對應的sql語句則是order by id。這種情況,當用戶傳參為id && 1=1 的時候,就會產生難以預計的後果。
解決方法
- 在原實體類裡加入一個map
public Map<String,String> indexMap=new HashMap<String,String>(){ { put("spaceId","space_id"); // key為前端傳的值,value為數據庫對應的列值 put("optTime","opt_time"); } };
- 當傳參時,判斷參數是否在map的key中,如果存在的話,就把對應的value作為排序的依賴條件。
if(paramOptLog.getOrderBy()!=null &&Strings.isNullOrEmpty(paramOptLog.getOrderBy())){ OptLog optLog=new OptLog(); paramOptLog.setOrderBy(optLog.indexMap.getOrDefault(paramOptLog.getOrderBy(), "id")); } List<OptLog> list = optLogMapper.query4Page(paramOptLog); }
- 總結就是通過映射,由程序員來決定 ${} 傳的參數,即將動態sql轉成靜態sql的方式可以解決這個問題,這樣在實際調用的時候就不會有sql註入的風險瞭。
mybatis sql註入問題之$與#
在mybatis中使用$符號
不會進行預編譯,會被sql註入
註入方式如下:
密碼隨便輸一個就可以通過驗證,隻要用戶名正確即可。
這樣輸入後查詢語句在數據庫中如下:
select id,username,password from userLogin where username='admin' OR 1=1 and password='23'
sql解釋:AND優先級高於OR 首先判斷後面1=1 and password=’23’為false,然後判斷前面username=’admin’為true中間
連接為OR即最後為true OR false 最後還是為true,就直接通過驗證,能夠正常登陸admin用戶。
在mybatis中使用#符號
這樣會進行預編譯,能夠防止sql註入。sql註入隻有在編譯時才有效,而預編譯的時候是用個?代替參數,真正執行時才把參數替換?。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。