天天看點

fastjson的這些坑,你誤入了沒?

背景:最近 fastjson 被爆出新的遠端代碼執行漏洞之後,趕緊督促項目組快馬加鞭去修改(吐槽:真改不動,架不住項目既多又老),鑒于項目不同,依賴的 fastjson 版本也不同,本次着重談 fastjson 1.2.16 版本遇到的那些問題?1

1

相容性:低版本沒問題,高版本抛異常 

一、抛問題。 摘取部分代碼片段,稍加改造如下。

引入依賴(低版本):

代碼跑起來(真爽,飛一般的感覺):

此時,把 fastjson 更新成高版本:

代碼跑起來(浪奔浪流,萬裡濤濤淚水永不休):

很明顯,第 31 行代碼抛出了異常

而且很明确:java.util.HashMap不能轉換成com.alibaba.fastjson.JSONObject。二、1.2.16 版本沒問題,更新到 1.2.70 就抛異常,敢問這是為什麼? 分析一:fastjson 1.2.16 版本下捉蟲子。

fastjson的這些坑,你誤入了沒?

分析二:fastjson 1.2.70 版本下捉蟲子。

fastjson的這些坑,你誤入了沒?

版本 1.2.16 vs 版本 1.2.70:

兩幅圖的标注 1 對比着看,會發現低版本的 JSONArray 中存進去的是 JSONObject,而高版本的存進去的是 HashMap;

兩幅圖的标注 2 對比着看,會發現低版本中 JSONObject 強轉成 JSONObject,當然沒問題,而高版本拿 HashMap 強轉成 JSONObject 就會出現 ClassCastException。

到這兒,感覺還不是很解氣,勢必要打破砂鍋刨到底!

版本 1.2.16 的源碼刨到底:

fastjson的這些坑,你誤入了沒?

而順着版本 1.2.16 的源碼一路看到底,會發現會對 Map 進行二次封裝處理,最終會包裝成 JSONObject 對象(這或許就是能強轉成 JSONObject 的原因,存進去的是牛,強轉成牛,當然沒問題)。

fastjson的這些坑,你誤入了沒?

版本 1.2.70 的源碼刨到底:

fastjson的這些坑,你誤入了沒?

版本 1.2.70 vs 版本 1.2.16,很顯然 1.2.70 版本增加了一個集合的條件分支判斷,如果根據 key 擷取的 value 是 List,則會建構 JSONArray 對象,如下面源碼截圖示意,List 裡面的值不會做變化,如果 List 中放入的是 Map,則不會對 Map 進行二次處理(這可能就是強制轉換成 JSONObect 失敗的原因,存進去的是牛,非要強轉成馬,當然行不通)。

fastjson的這些坑,你誤入了沒?

三、該怎麼解決版本更新,帶來的相容性問題呢?

很簡單,既然高版本的沒有對 list 中的 Object 進行轉換,咱們就刻意調用 toJSON 方法進行轉換一番。

代碼跑起來,Debug 看看效果如何:

fastjson的這些坑,你誤入了沒?

很明顯,JSONArray 中擷取的 object 類型已變為 JSONObject,當然在 1.2.16、1.2.70 版本跑起來都暢通無阻,那麼版本更新帶來的問題就迎刃而解。 四、閑扯淡(走心)

寫代碼時候還是需要注意點,能稍微規範些,就盡量按照規範,就如本次提到的問題,向 JSONObject 中加入 List<Map<String,Object> 時,不妨先提前 toJSON 轉換一番,這樣版本更新也不會有問題。

由于依賴包更新導緻不相容的情況很常見,不過絕大多數都是向下相容的,例如 JDK ... 5、6、7、8 ...,是以如果你正在開發核心代碼,若涉及到版本更新,盡量考慮相容性問題,如果涉及到老功能廢棄時,不妨采用注解标注一下,這樣後人會盡早發現問題。

2

 不規範的傳入:導緻記憶體溢出  

分享一段有意思的代碼,一起享受其中樂趣。

代碼能跑起來,運作結果絕對正常

此時,我們動點手腳,把 value1 的值變掉

程式運作,word 天,驚呆!

好奇不?咋回事?Debug 分析一番就清楚啦。

fastjson的這些坑,你誤入了沒?

當 json 字元串是以 \x 結尾時,由于低版本的 fastjson 并未對其進行校驗,将會導緻其繼續嘗試擷取字元。

fastjson的這些坑,你誤入了沒?

由于 index>= this.len 始終成立,則意味着會直接擷取到 \u001A,相當于 26,帶來的結果就是 isEOF 永遠為 false,意味着要無休止的讀下去。

fastjson的這些坑,你誤入了沒?

就這樣陷入了死循環 1-->2-->3-->1,直到記憶體溢出。

fastjson的這些坑,你誤入了沒?

Debug 一趟肯定比我說的要清楚,當然,此問題早已在版本 1.2.60 中修複。

fastjson的這些坑,你誤入了沒?

1.2.70 版本肯定也不會有此問題啦,在高版本下直接提示格式錯誤啦,擺脫了記憶體異常。

走心:

金無足赤人無完人,代碼有 Bug 很正常,需要一步一步去疊代,要敢于讓團隊犯錯、試錯、容錯。

通過此段測試,項目開發中參數格式校驗就很有必要。

3

寄語寫最後

本次,僅以項目中依賴 fastjson 類庫作為切入點,主要想傳達:在使用三方輪子時,盡可能做對三方的輪子了如之掌,知己知彼方能百戰不殆。

另外,借助 fastjson 更新的事情,也想傳達寫出規範性的代碼,是很有必要,不然更新的時候就很麻煩。

https://mp.weixin.qq.com/s/FTZDrkvOpdLVWtuY42IUuw