工作發狂:Mybatis 中$和#千萬不要亂用!

孤獨鍵客發表於2019-05-09
閱讀本文大概需要 2.2 分鐘。

作者:程式猿的內心獨白

開頭

這是一次程式碼最佳化過程中發現的問題,在功能最佳化後發現部分資料查不到出來了,問題就在於一條sql上的#和$。

下圖為兩條sql:

工作發狂:Mybatis 中$和#千萬不要亂用!

從圖上可以看出 wwlr.LabelId in(${showLabels}) 和 wwlr.LabelId in(#{showLabels}),其中showLabels是傳進來一個字串型別的引數,引數的樣子是這樣的“4,44,514”,問題就出在這個引數傳進來後#和$處理的方式是不一樣的。

區別

1、#{ }是預編譯處理,MyBatis在處理#{ }時,它會將sql中的#{ }替換為?,然後呼叫PreparedStatement的set方法來賦值,傳入字串後,會在值兩邊加上單引號,如上面的值 “4,44,514”就會變成“ '4,44,514' ”;

2、${ }是字串替換, MyBatis在處理${ }時,它會將sql中的${ }替換為變數的值,傳入的資料不會加兩邊加上單引號。

注意:使用${ }會導致sql注入,不利於系統的安全性!

SQL隱碼攻擊:就是透過把SQL命令插入到Web表單提交或輸入域名或頁面請求的查詢字串,最終達到欺騙伺服器執行惡意的SQL命令。常見的有匿名登入(在登入框輸入惡意的字串)、藉助異常獲取資料庫資訊等

應用場合:

1、#{ }:主要使用者獲取DAO中的引數資料,在對映檔案的SQL語句中出現#{}表示式,底層會建立預編譯的SQL;

2、${ }:主要用於獲取配置檔案資料,DAO介面中的引數資訊,當$出現在對映檔案的SQL語句中時建立的不是預編譯的SQL,而是字串的拼接,有可能會導致SQL隱碼攻擊問題.所以一般使用$接收dao引數時,這些引數一般是欄位名,表名等,例如order by {column}。

注:

${}獲取DAO引數資料時,引數必須使用@param註解進行修飾或者使用下標或者引數#{param1}形式;

#{}獲取DAO引數資料時,假如引數個數多於一個可有選擇的使用@param。

問題分析

其實剛開始我也沒太去看sql裡的#和$,我把sql放到資料庫跑一切正常,所以我就將程式碼的執行sql輸出到控制檯了,具體是這麼一個輸出sql的配置檔案:

工作發狂:Mybatis 中$和#千萬不要亂用!

輸出後,終於發現了問題在哪裡。。。。

看了上面的區別介紹,相信大家其實都應該知道區別在哪裡,我們的問題在哪裡,其實就是sql在in的時候 ,裡面的資料被加了兩個雙引號。“wwlr.LabelId in(4,44,514)就會變成 wwlr.LabelId in('4,44,514' );所以導致部分資料查不到了。

解決辦法

1、快速解決

最快的方法就是把#直接替換成$,這樣問題應該就可以解決了。

但是,我很無語,我確沒有解決。

本地跑程式碼一點問題都沒有,部署到公司的docker上問題一樣沒解決,給人的感覺就是程式碼根本沒有從#變$。

大家都知道$其實是有危險性,會容易被sql注入,具我所知道,我們公司的docker是會加一層防止 sql注入的功能 ,所以不知道是不是這個功能把的$無效掉了。

當然,我也沒有去再到服務上打出sql來看一下,因為本來$就是不太安全的,所以我換了一種方式處理。

2、foreach標籤的使用

foreach標籤主要用於構建in條件,他可以在sql中對集合進行迭代。

先來看看語法:

工作發狂:Mybatis 中$和#千萬不要亂用!

透過上圖,大家也應該也瞭解和使用這個標籤了吧。

那對於我們專案中的改造,其實就是把原來傳進來的字元型引數變成List<Integer>,這樣問題就完美的解決了,既實現了我們的功能 ,又解決了安全性問題。

原文連結:



·END·

程式設計師的成長之路

路雖遠,行則必至

本文原發於 同名微信公眾號「程式設計師的成長之路」,回覆「1024」你懂得,給個讚唄。

回覆 [ 520 ] 領取程式設計師最佳學習方式

回覆 [ 256 ] 檢視 Java 程式設計師成長規劃


往期精彩回顧


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69902700/viewspace-2643759/,如需轉載,請註明出處,否則將追究法律責任。

相關文章