SQL隱碼攻擊問題
概述:
直接原因:
根本原因:伺服器端沒有嚴格檢驗使用者資料導致SQL隱碼攻擊漏洞,像使用JDBC的Statement語句新增SQL語句,如下:
由於我們的JDBC在對資料庫進行操作時,需要使用者端傳入一些引數。我們在日常中的處理是將字串引數作為SQL語句進行拼接,但是加入使用者端傳入SQL語句關鍵字惡意篡改SQL語句就會改變伺服器端SQL語意發生系統異常。嚴重時就會導致系統和資料庫破壞,這時的攻擊方式就叫SQL隱碼攻擊了。
範例:模擬登入請求傳入使用者id和密碼引數,使用字串拼接導致的SQL隱碼攻擊。
拼接SQL語句,就會出現SQL隱碼攻擊的安全問題,拼接程式碼如下:
String sql = "select * from user where username='" + uid + "' and password='" + passwd + "'";
若此時傳入引數如下:永真式萬能密碼 或 封號結束註釋後面條件驗證(只能說人的腦洞真大哈哈),還有更奇葩的像 Union
注入
params.put("uid", "malongfei");
params.put("passwd", "111' or '1' = '1");
// 或者
params.put("uid", "malongfei'; -- ")
// 或者
params.put("uid", "malongfei'; # ")
此時JDBC還沒意識到安全問題,依舊將以上引數拼接到我們的SQL原語中,如下:
select * from user where uid = 'malongfei' and passwd = '111' or '1' = '1';
select * from user where uid = 'malongfei'; -- ' and passwd = '111' or '1' = '1';
select * from user where uid = 'malongfei'; # ' and passwd = '111' or '1' = '1';
預防SQL隱碼攻擊:使用PreparedStatement代替Statement可以有效防止SQL隱碼攻擊。
// 後端登入驗證密碼介面的SQL語句
select * from user where uid = ? and passwd = ?;
PreparedStatement 與 Statment 區別:
Mybatis對SQL隱碼攻擊的預防處理
出現SQL隱碼攻擊問題的原因和上面一樣,都是由於拼接SQL導致的,只不過方式不同。
#{}
和 ${}
,#
使用預編譯,$
使用拼接SQL方式。mybatis 出現SQL隱碼攻擊範例:
模糊查詢時,如下範例:
採用 #{}
的話程式會報異常。最後替換成 like "'name'"
select * from users where name like '%#{name}%'
常人看了既然#{}報錯那麼我用${},正中SQL隱碼攻擊的下懷,這個時候倘若我們的伺服器端 Java 程式碼沒有對傳入引數進行攔截處理,SQL隱碼攻擊條件滿足!
select * from users where name like '%${name}%'
正確SQL寫法,需要使用 concat函數 來進行連線引數(concat為mysql函數,連線引數產生字串)
select * from users where name like concat('%',#{name}, '%')
補充:
in
之後的多個引數在mybatis中也不能採用 #{}
或者 ${}
,需要使用動態SQL語法中 foreach
迴圈遍歷
select * from users where id in
<foreach collection="ids" item="item" open="("separatosr="," close=")">
#{item}
</foreach>
order by
之後也不能使用 #{}
,他也會將欄位改為字串形式,加上引號後就不能正常排序,所以我們需要考慮 ${}
的方式,但是在後臺程式碼中一定要進行資料引數的校驗等手段,防止SQL隱碼攻擊.