我曾經寫過一篇文章java
文章曾經比較詳細分析了fastjson
在1.2.24以及以前版本存在遠程代碼執行高危安全漏洞的問題。json
本文則是針對另外一個漏洞的介紹和分析。安全
官方對此次漏洞的說明是這樣的:服務器
近日,阿里雲應急響應中心監測到fastjson爆出遠程拒絕服務漏洞,攻擊者在請求中構造特定json字符串,可遠程形成服務器內存和CPU等資源耗盡,最終拒絕服務。官方已發佈公告說明,最新的1.2.60和帶有sec06字符的版本不受影響,請使用到的用戶儘快升級至安全版本。
fastjson處理x轉義字符不當,攻擊者在請求中構造特定json字符串可致使服務器內存和CPU等資源耗盡,最終拒絕服務。阿里雲應急響應中心提醒fastjson用戶儘快採起安全措施阻止漏洞攻擊。app
官方說的很明白了,咱們根據這段說明來構造一個「死亡」字符串重現下。this
public class App { static final String DEATH_STRING = "{\"a\":\"\\x"; public static void main(String[] args) { try { JSON.parse(DEATH_STRING); } catch (Exception e) { e.printStackTrace(); } } }
運行這段代碼,你會發現這段不足10行的代碼竟然能夠致使OOM。阿里雲
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at com.alibaba.fastjson.parser.JSONLexerBase.putChar(JSONLexerBase.java:5041) at com.alibaba.fastjson.parser.JSONLexerBase.scanString(JSONLexerBase.java:889) at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:483) at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1394) at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1360) at com.alibaba.fastjson.JSON.parse(JSON.java:165) at com.alibaba.fastjson.JSON.parse(JSON.java:175) at com.alibaba.fastjson.JSON.parse(JSON.java:144) at com.app.App.main(App.java:21)
咱們能夠順着這個異常信息,擼一擼源碼,看看究竟是哪裏的BUG。spa
如上圖所示,當解析到字符x
時,由於是最後一個字符,因此x1和x2都是\u001A
,也就是十進制的26。由於每次char ch = this.next();
獲取的都是26這個字符,而後就在第三張圖的位置死循環了。.net
有人可能會問,
if (this.isEOF())
這個語句爲啥沒有生效,不是已經到告終尾了嗎?那咱們來看看isEOF
的實現,
public boolean isEOF() { return this.bp == this.len || this.ch == 26 && this.bp + 1 == this.len; }
由於前面兩次next
操做,bp+1已經不等於len了,(你能夠單步調試看看),因此isEOF
方法永遠返回false
。
官方已經給出瞭解決方案,那就是升級fastjson
到1.2.60或以上版本。
我以爲做爲一個優秀的程序員,既然知其然,也要知其因此然。咱們來看看阿里的優秀工程師是如何修復這個漏洞的。咱們把fastjson升級到1.2.60
,而後繼續debug源碼,發現代碼變成了這樣:
這種解決方案雖然簡單粗暴,可是也是頗有效的不是嗎,哈哈!
com.alibaba.fastjson.JSONException: invalid escape character \x at com.alibaba.fastjson.parser.JSONLexerBase.scanString(JSONLexerBase.java:983) at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:483) at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1397) at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1363) at com.alibaba.fastjson.JSON.parse(JSON.java:170) at com.alibaba.fastjson.JSON.parse(JSON.java:180) at com.alibaba.fastjson.JSON.parse(JSON.java:149) at com.app.App.main(App.java:25)