经过多方调研,最终还是决定禁用FastJson!

简介: 经过多方调研,最终还是决定禁用FastJson!

老项目中使用到多种json类库,没有统一管理。最近开启全新的项目,准备对json类库进行统一,这样不仅能够压缩jar包的大小,也能够避免某个类库的漏洞导致系统问题。

其实,就在前几个月因为FastJson的漏洞,已经全面升级过一次FastJson的版本。现在项目中有用FastJson,有用gson,也有用Jackson。虽然用的类库比较多,但使用的场景并不多,还在可控范围之内。

这篇文章重点讲讲对FastJson的一些调研,虽然最终决定强制在项目中禁用FastJson,但在放弃之前,还是要学习一下这个类库的。

FastJson简介

Fastjson是阿里巴巴的开源JSON解析库,基于Java语言,支持JSON格式的字符串与JavaBean之间的相互转换。它采用一种“假定有序快速匹配”的算法,把JSON Parse的性能提升到了极致。

由于接口简单易用,已经被广泛使用在缓存序列化,协议交互,Web输出等各种应用场景中。

FastJson的简单示例

先用一个简单的示例来演示一下FastJson的使用。先在项目中引入FastJson类库:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.70</version>
</dependency>

关于版本至少要在1.2.70以上,为啥?之前版本的漏洞太多。

定义个JavaBean,我们拿User为例:

public class User {
    private String userName;
    private int age;
    private String address;
    // getter/setter
}

使用实例:

public static void main(String[] args) {
    String json = "{\"address\":\"Beijing\",\"age\":28,\"user_name\":\"Tom\"}";
    // 将json转换为JavaBean
    User user = JSONObject.parseObject(json, User.class);
    System.out.println(user);
    // 将JavaBean转换为json
    String result = JSONObject.toJSONString(user);
    System.out.println(result);
}

实例中先将json字符串通过parseObject转换成User对象,然后又将User对象通过toJSONString方法转换成json。用起来是不是非常方便?

同时在构造json时你是否发现json字符串中有“user_name”这样的格式,FastJson默认会将这种下划线格式的key,与JavaBean中驼峰格式的属性进行绑定。

执行程序,打印结果:

User(userName=Tom, age=28, address=Beijing)
{"address":"Beijing","age":28,"userName":"Tom"}

可以看出成功执行。

FastJson还有其他一些常用的API,比如:

public static final Object parse(String text); // 把JSON文本parse为JSONObject或者JSONArray 
public static final JSONObject parseObject(String text); // 把JSON文本parse成JSONObject    
public static final <T> T parseObject(String text, Class<T> clazz); // 把JSON文本parse为JavaBean 
public static final JSONArray parseArray(String text); // 把JSON文本parse成JSONArray 
public static final <T> List<T> parseArray(String text, Class<T> clazz); //把JSON文本parse成JavaBean集合 
public static final String toJSONString(Object object); // 将JavaBean序列化为JSON文本 
public static final String toJSONString(Object object, boolean prettyFormat); // 将JavaBean序列化为带格式的JSON文本 
public static final Object toJSON(Object javaObject); //将JavaBean转换为JSONObject或者JSONArray。

通过上述API还可以实现:json字符串与JSONArray之间的转换、json字符串与javaBean之间的转换、json字符串-数组类型与javaBean之间的转换、JavaList与JsonArray之间的转换等。

为什么决定放弃FastJson

通过上面的示例来看FastJson的API使用起来也是非常简单,而且它的特点,也就是卖点就是“快”。

虽然网上有各种测试,质疑FastJson的“快”,但排除测试者测试用例或环境的影响,整体来看FastJson并不比市面上的其他同类框架慢。

那么放弃使用的原因是什么呢?

流行度

首先,它并不像我们想象中那么大受欢迎。来看一下FastJson的Maven引用量数据统计(来源https://mvnrepository.com/):

image.png可以看出FastJson排行第四,仅次于第三位的JSON In Java。如果考虑到国内大多数用阿里镜像,那么FastJson的排位要更靠前一些,但与Jackson相比差距还是有的。

设计与代码质量

在国外没有更受推广的原因大概有两个:推广(外加英文文档)和代码质量。

外国友人不喜欢FastJson是因为感觉代码质量不高。知乎上有一篇相关的文章,虽然写2016年,但也可以参考一下(链接:https://www.zhihu.com/question/44199956)。

image.png对于上述原因,我个人倒是更看重高赞回答中的总结“用很多投机取巧的的做法去实现所谓的'快',而失去了原本应该兼容的java特性,对json标准遵循也不严格”。

是的,正是因为这个类库来源于阿里的实践,很多最初的设计与标准有一定的差距。而且已经被大量应用,就很难在后期改动。外加还经常出现不兼容性升级。

开源Issues

在写这篇文章时,看了一下GitHub上项目的Issues,还有大量的需要修复的问题。而且版本还在频繁的更新,修复升级。image.png还有1488个问题处于Open状态!看到此处,真的有些担心了。用的人多,提问题的人多,也可以从另外一个方面来说可能更安全,但如果还有这么多问题待解决,还是有些恐怖的。

漏洞修复历史

同时,前段时间FastJson多次被爆存在漏洞,而这些漏洞都与FastJson中的一个AutoType特性有关。

从2019年7月份发布的v1.2.59一直到2020年6月份发布的 v1.2.71 ,每个版本的升级中都有关于AutoType的升级。

1.2.59发布,增强AutoType打开时的安全性 fastjson
1.2.60发布,增加了AutoType黑名单,修复拒绝服务安全问题 fastjson
1.2.61发布,增加AutoType安全黑名单 fastjson
1.2.62发布,增加AutoType黑名单、增强日期反序列化和JSONPath fastjson
1.2.66发布,Bug修复安全加固,并且做安全加固,补充了AutoType黑名单 fastjson
1.2.67发布,Bug修复安全加固,补充了AutoType黑名单 fastjson
1.2.68发布,支持GEOJSON,补充了AutoType黑名单。(引入一个safeMode的配置,配置safeMode后,无论白名单和黑名单,都不支持autoType。) fastjson
1.2.69发布,修复新发现高危AutoType开关绕过安全漏洞,补充了AutoType黑名单 fastjson
1.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的漏洞问题还是给予理解和包容。

目录
相关文章
|
数据库 OceanBase
OceanBase 数据库的版本信息
OceanBase 数据库的版本信息
3307 1
|
10月前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
2796 31
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
JSON 安全 fastjson
FastJSON库:JSON处理效率与安全性评估
FastJSON库:JSON处理效率与安全性评估
|
Java 网络安全 开发工具
【Azure 事件中心】Event Hub 无法连接,出现 Did not observe any item or terminal signal within 60000ms in 'flatMapMany' 的错误消息
【Azure 事件中心】Event Hub 无法连接,出现 Did not observe any item or terminal signal within 60000ms in 'flatMapMany' 的错误消息
454 1
|
11月前
|
网络安全 数据安全/隐私保护
堡垒机上的主机连接本地sftp报错链接被意外关闭
【10月更文挑战第3天】堡垒机上的主机连接本地sftp报错链接被意外关闭
588 1
|
存储 监控 安全
在Linux中,如何进行安全审计?
在Linux中,如何进行安全审计?
|
网络协议 Shell 网络安全
开发工具使用之 github 私人仓库Clone 失败的问题
这篇文章介绍了解决GitHub上私人仓库克隆失败的问题,通过检查本地SSH key的存在与否、生成新的SSH key、添加SSH key到GitHub以及使用SSH方式克隆私有仓库的步骤来解决这个问题。
开发工具使用之 github 私人仓库Clone 失败的问题
|
计算机视觉
【YOLOv10改进-卷积Conv】动态蛇形卷积(Dynamic Snake Convolution)用于管状结构分割任务
YOLOv10专栏介绍了一种用于精确分割管状结构的新方法DSCNet,它结合了动态蛇形卷积、多视角融合和拓扑连续性约束损失。DSConv创新地聚焦细长局部结构,增强管状特征感知,而多视角融合和TCLoss则改善了全局形态理解和分割连续性。在2D和3D数据集上的实验显示,DSCNet在血管和道路等分割任务上超越了传统方法。DySnakeConv模块整合到YOLOv10中,提升了目标检测的准确性。[链接指向详细文章](https://blog.csdn.net/shangyanaf/article/details/140007047)
|
JSON fastjson Java
Spring Boot Jackson 和Fast JSON 用哪个好啊 ?
【4月更文挑战第22天】
2525 1
|
JavaScript 关系型数据库 Java
MyBatisPlus 最新版代码生成器(直接拿来就能用,包含自动生成 Vue 模版)
MyBatisPlus 最新版代码生成器(直接拿来就能用,包含自动生成 Vue 模版)
2805 0