当前位置: 首页 > 科技观察

经过多方考察,最终决定禁用FastJson!

时间:2023-03-21 21:05:07 科技观察

本文转载自微信公众号《程序新视野》,作者为二哥。转载本文请联系程序新视界公众号。老项目中使用了各种json库,没有统一管理。最近开始一个全新的项目,准备统一json类库,这样既可以压缩jar包的大小,又可以避免某个类库有漏洞导致系统出现问题。事实上,就在几个月前,因为FastJson的漏洞,FastJson的版本已经全面升级。现在项目使用FastJson、gson、Jackson。虽然用到的类库很多,但是用到的场景不多,还在可控范围内。本文重点对FastJson进行一些研究。虽然最终决定在项目中强制禁用FastJson,但是还是要学习这个类库才可以放弃。FastJson简介Fastjson是阿里巴巴开源的JSON解析库,基于Java语言,支持JSON格式字符串与JavaBean之间的转换。它采用了一种“假定有序快速匹配”的算法,将JSONParse的性能提升到极致。由于界面简单易用,被广泛应用于缓存序列化、协议交互、Web输出等各种应用场景。FastJson的一个简单例子首先用一个简单的例子来演示FastJson的使用。首先在项目中引入FastJson类库:com.alibabafastjson1.2.70版本必须在至少1.20.70以上,为什么?以前的版本有太多的错误。定义一个JavaBean,我们以User为例:publicclassUser{privateStringuserName;privateintage;privateStringaddress;//getter/setter}用法举例:publicstaticvoidmain(String[]args){Stringjson="{\"address\":\"北京\",\"age\":28,\"user_name\":\"Tom\"}";//将json转JavaBeanUseruser=JSONObject.parseObject(json,User.class);System.out.println(user);//将JavaBean转换为jsonStringresult=JSONObject.toJSONString(user);System.out.println(result);}在实例中,首先将json字符串通过parseObject转换为User对象,然后再转换User对象通过toJSONString方法json传递给User对象。使用起来是不是很方便?同时,在构造json的时候,有没有发现json字符串中有“user_name”这样的格式?默认情况下,FastJson会将这种下划线格式的key绑定到JavaBean中驼峰格式的属性上。执行程序,打印结果:User(userName=Tom,age=28,address=Beijing){"address":"Beijing","age":28,"userName":"Tom"}可以看出执行成功。FastJson还有一些其他常用的API,如:publicstaticfinalObjectparse(Stringtext);//将JSON文本解析成JSONObject或JSONArraypublicstaticfinalJSONObjectparseObject(Stringtext);//将JSON文本解析成JSONObjectpublicstaticfinalTparseObject(Stringtext,Classclazz);//将JSON文本解析成JavaBeanpublicstaticfinalJSONArrayparseArray(Stringtext);//将JSON文本解析成JSONArraypublicstaticfinalListparseArray(Stringtext,Classclazz);//将JSON文本解析成JavaBean集合publicstaticfinalStringtoJSONString(Objectobject);//将JavaBean序列化为JSON文本publicstaticfinalStringtoJSONString(Objectobject,booleanprettyFormat);//将JavaBean序列化为格式化的JSON文本publicstaticfinalObjecttoJSON(ObjectjavaObject);//将JavaBean转换为JSONObject或JSONArray。通过上面的API,还可以实现:json字符串与JSONArray的转换、json字符串与javaBean的转换、json字符串-数组类型与javaBean的转换、JavaList与JsonArray的转换等等。为什么决定给upFastJson从上面的例子我们可以看出,FastJson的API使用起来也非常简单,而且它的特点,也就是它的卖点就是“快”。虽然网上有各种测试质疑FastJson的“快”,但排除测试人员测试用例或环境的影响,FastJson整体上并不比市面上其他同类框架慢。那么放弃它的原因是什么?受欢迎程度首先,它并不像我们想象的那样受欢迎。我们来看一下FastJson的Maven参考统计(来源https://mvnrepository.com/):fastjson可以看到FastJson排名第四,仅次于JSONInJava,排名第三。如果考虑到国内大部分使用阿里镜像,那么FastJson的排名更高,但是和Jackson相比还是有差距的。设计和代码质量在国外不太流行的原因大概有两个:推广(加上英文文档)和代码质量。国外的朋友不喜欢FastJson,就是觉得代码质量不高。知乎上有相关文章。虽然是2016年写的,大家也可以参考一下(链接:https://www.zhihu.com/question/44199956)。基于以上原因,我个人比较看重高赞回答中的总结:“用了很多投机取巧的方法来达到所谓的‘快’,但是丢失了应该兼容的Java特性,json标准是没有严格遵守。”是的,正因为这个类库来源于阿里的实践,很多初期的设计与标准有一定的差距。而且,它已经被广泛使用,所以以后很难改变它。此外,还有频繁的不兼容升级。OpenSourceIssues在写这篇文章的时候,我看了看GitHub上项目的Issues,还有很多问题需要修复。并且版本还在频繁的更新、修复和升级。fastjson还有1488个未解决的问题!看到这里,我真的很担心。用的人多,问的人也多,从另一个方面来说可能更安全,但是要解决这么多问题,还是有点吓人。漏洞修复历史同时,前段时间FastJson多次被曝存在漏洞,而这些漏洞都与FastJson中的一个AutoType特性有关。从2019年7月发布的v1.2.59到2020年6月发布的v1.2.71,每次版本升级都有关于AutoType的升级。1.2.59发布,增强打开AutoType时的安全性fastjson1.2.60发布,添加AutoType黑名单,修复拒绝服务安全问题fastjson1.2.61发布,添加AutoType安全黑名单fastjson1.2.62发布,添加AutoType黑名单,增强日期反序列化和JSONPathfastjson1.2.66发布,bug修复安全加固,安全加固,补充AutoType黑名单fastjson1.2.67发布,bug修复安全加固,补充AutoType黑名单fastjson1.2.68发布,支持GEOJSON,补充AutoType黑名单。(引入一个safeMode配置,配置safeMode后,无论白名单还是黑名单,autoType都不支持。)fastjson1.2.69发布,修复新发现的高危AutoType开关绕过安全漏洞,补充AutoType黑名单fastjson1.2.70发布,提高兼容性,补充AutoType黑名单那么什么是AutoType呢?为什么会造成漏洞?对于JSON框架,Java对象到字符串的转换通常可以基于属性或setter/getter方法。FastJson和Jackson遍历了类中所有的getter方法,Gson通过反射遍历了类中的所有属性,并将它们的值序列化为json。.当类中包含接口(或抽象类)时,使用FastJson进行序列化时,子类型会被擦除,只保留接口(抽象类)的类型,这样反序列化时就无法获取到原始类型。所以FastJson引入了AutoType来记录序列化时的原始类型。有了autoType函数,FastJson在反序列化JSON字符串时,会读取@type到内容中,尝试将JSON内容反序列化为一个对象,并调用其setter方法。使用这个特性,你可以构造一个JSON字符串,并使用@type指定你想要使用的攻击库。总结虽然FastJson有这么多问题,决定不再使用FastJson,但也正如知乎网友所说,“文少几乎支持了一个自己广泛使用的JSON库,而其他库几乎都依赖于一个整个团队,基于在这一点上,不愧为“阿里开源第一人,初心不改”。“对于FastJson的漏洞,我还是给予理解和宽容。