本篇內(nèi)容介紹了“fastjson漏洞導(dǎo)致服務(wù)癱瘓問題分析”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!
成都創(chuàng)新互聯(lián)長期為近1000家客戶提供的網(wǎng)站建設(shè)服務(wù),團隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為左權(quán)企業(yè)提供專業(yè)的成都做網(wǎng)站、網(wǎng)站制作、成都外貿(mào)網(wǎng)站建設(shè),左權(quán)網(wǎng)站改版等技術(shù)服務(wù)。擁有10多年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。
??2019年9月5日,fastjson修復(fù)了當字符串中包含\x轉(zhuǎn)義字符時可能引發(fā)OOM的問題。建議廣大用戶升級fastjson版本至少到1.2.60。
??一個bug這么恐怖,竟然直接OOM,親身體驗下吧。測試代碼如下:
JSON.parse("[{\"a\":\"a\\x]");
實驗效果:4分鐘 堆內(nèi)存 占用上升達2G;
??fastjson升級幾天后,一老系統(tǒng)業(yè)務(wù)發(fā)生異常,異常信息如下:
Exception in thread "xxx" com.alibaba.fastjson.JSONException: expect ':' at 0, actual = at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:290) at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1380) at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1346) at com.alibaba.fastjson.JSON.parse(JSON.java:156) at com.alibaba.fastjson.JSON.parse(JSON.java:166) at com.alibaba.fastjson.JSON.parse(JSON.java:135) at com.alibaba.fastjson.JSON.parseObject(JSON.java:227) at alibaba.fastjson.FastJsonBug.main(FastJsonBug.java:70)
??看這錯誤,肯定是json字符串格式有誤,應(yīng)該是冒號的地方實際上是等號了,然后導(dǎo)致反序列化異常,果斷排查接口入?yún)ⅲY(jié)果入?yún)⒁磺姓?。納尼。。。
??好吧,那就本地debug吧,結(jié)果竟然在本地復(fù)現(xiàn)異常了,震驚!??!再次檢查接口入?yún)?,沒有問題,和以前正常運行的入?yún)⑹且恢碌?。想到最近升級fastjson了,還原fastjson版本試試吧。還原后還真是正常了!??!
??難道fastjson版本升級出了大bug?
??本著對阿里技術(shù)的信任,我決定一探究竟。
??待反序列化的數(shù)據(jù),其格式是2層List嵌套,測試代碼已做脫敏處理(完整源碼見后文github地址):
String json = "{\"bvos\":[{\"names\":[\"zxiaofan\"]}]}"; JSONObject jsonObjectB1 = GSON.fromJson(json, JSONObject.class); JSONArray jsonArrayB = jsonObjectB1.getJSONArray("bvos"); JSONObject jsonObjectB2 = JSONObject.parseObject(jsonArrayB.get(0).toString()); // 上面這行代碼直接異常了,異常信息如下: // com.alibaba.fastjson.JSONException: expect ':' at 0, actual =
??好奇寶寶們就不要糾結(jié)于為什么沒有定義好實體再使用TypeReference一步到位啦,千年老代碼確實是這樣的,這也不是本文的重點。
??經(jīng)過debug發(fā)現(xiàn),jsonArrayB.get(0).toString()的值是 {names=[zxiaofan]}。注意了,names后面是等號,不是冒號,這也就能解釋為什么異常是“expect ':' at 0, actual =”了。
??但為什么升級后就異常,沒升級就一切正常呢?繼續(xù)研究下,梳理后發(fā)現(xiàn)如下值得注意的地方:
1、fastjson版本時1.2.54時正常,大于1.2.54后便會異常;
2、運行代碼是Google的Gson和阿里的fastjson混用的(json處理全部換成fastjson一切正常);
??莫非,是fastjson升級后和Google的Gson不兼容導(dǎo)致?
仿佛看到了曙光。
??對比分析了fastjson 1.2.54版本和其之后的版本(以下以1.2.55版本為例),發(fā)現(xiàn)getJSONArray(String key)還真有區(qū)別。
// fastjson1.2.54 public JSONArray getJSONArray(String key) { Object value = this.map.get(key); if (value instanceof JSONArray) { return (JSONArray)value; } else { return value instanceof String ? (JSONArray)JSON.parse((String)value) : (JSONArray)toJSON(value); } }
// fastjson1.2.55 public JSONArray getJSONArray(String key) { Object value = this.map.get(key); if (value instanceof JSONArray) { return (JSONArray)value; } else if (value instanceof List) { return new JSONArray((List)value); } else { return value instanceof String ? (JSONArray)JSON.parse((String)value) : (JSONArray)toJSON(value); } }
??經(jīng)過調(diào)試后發(fā)現(xiàn),1.2.54版本在getJSONArray(String key)方法中使用的是(JSONArray)toJSON(value),而1.2.55版本在getJSONArray(String key)方法中使用的是return new JSONArray((List)value)。兩者處理后返回的數(shù)據(jù)也確實不同。
fastjson 1.2.54 版本:
fastjson 1.2.55 版本:
??從調(diào)試情況看,1.2.54版本最終返回的是JSONObect,1.2.55版本返回的是LinkedTreeMap。Map結(jié)構(gòu)toString()的結(jié)構(gòu)肯定是“key=value”,而不是json結(jié)構(gòu)。
??但是如果將測試代碼中的GSON.fromJson替換成JSON.parseObject,那么不論fastjson的版本高低,都能正常運行。
??至此,我們知道了,fastjson在升級到1.2.55及以上版本后,getJSONArray方法對Google的Gson處理后的數(shù)據(jù)兼容性降低,或許本文的名字叫做《fastjson與Gson混用引發(fā)的bug》更合適。
??也不知道這算不算是bug,給官方提了個issue: > fastjson版本升級降低了對Gson的兼容性 #2814。
??在分析的過程中,看了fastjson中g(shù)etJSONArray方法對各種數(shù)據(jù)類型的處理方式,和自己以前寫的類似代碼相比fastjson的代碼更優(yōu)雅,值得學(xué)習(xí)。相關(guān)方法com.alibaba.fastjson.JSON.toJSON(),有興趣的同學(xué)可以看看。
// 此處代碼僅展示核心結(jié)構(gòu),如需查閱完整代碼請前往github/fastjson查看。 // toJSON簡直是 數(shù)據(jù)類型分類處理的模板。@zxiaofan @SuppressWarnings("unchecked") public static Object toJSON(Object javaObject, SerializeConfig config) { if (javaObject == null) { return null; } if (javaObject instanceof JSON) { return javaObject; } if (javaObject instanceof Map) { if (map instanceof LinkedHashMap) { } else if (map instanceof TreeMap) { } else { innerMap = new HashMap(size); } return json; } if (javaObject instanceof Collection) { for (Object item : collection) { } return array; } if (javaObject instanceof JSONSerializable) { return JSON.parse(json); } Class clazz = javaObject.getClass(); if (clazz.isEnum()) { return ((Enum) javaObject).name(); } if (clazz.isArray()) { for (int i = 0; i < len; ++i) { } return array; } if (ParserConfig.isPrimitive2(clazz)) { return javaObject; } ObjectSerializer serializer = config.getObjectWriter(clazz); if (serializer instanceof JavaBeanSerializer) { return json; } String text = JSON.toJSONString(javaObject); return JSON.parse(text); }
“fastjson漏洞導(dǎo)致服務(wù)癱瘓問題分析”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!