Fastjson 开发随笔

常见使用问题

safeMode 导致反序列化失败

问题描述

Bean 对象序列化后的字符串包含 @type 字段:

1
{ "@type": "com.clay.system.model.User", "name": "peter" }

使用 Fastjson 将字符串反序列化为 Bean 对象(反序列化时没有指定 Class 类型):

1
User user = (User) JSON.parse(jsonString);

Bean 对象会反序列化失败,并抛出以下异常:

1
Could not deserialize: safeMode not support autoType : com.clay.system.model.User

问题分析

Fastjson 在 1.2.68 及之后版本引入了 safeMode 安全机制,开启 safeMode 安全机制后会完全禁止 autoType(自动类型识别),即使通过代码设置了白名单或者黑名单,autoType 也不会生效,从而会导致反序列化包含 @type 字段的 JSON 字符串时直接抛出异常,这样可以杜绝反序列化 Gadgets 类变种攻击。在部分项目中,首次反序列化操作可能触发 safemode 校验逻辑,而后续操作因缓存机制未再次触发异常‌。

版本区别

  • Fastjson 2.x 默认启用了 safeMode 安全机制‌,也就是默认禁用了 autoType 自动类型识别。
  • Fastjson 1.2.x 如果需要启用 safeMode 安全机制‌,则需要手动调用 ParserConfig.setSafeMode(true),而 2.x 版本默认启用了 safeMode 安全机制。

特别注意

  • 如果 Fastjson 的版本号带有 _noneautotype 后缀(比如 1.2.83_noneautotype),则说明该版本是不支持 autoType 的特殊构建版本,默认完全禁用了 autoType
  • Fastjson 的 _noneautotype 版本即使通过代码设置了白名单或者黑名单,autoType 也不会生效,详细说明请看这里

问题解决

  • (1) 使用 JSON.parseObject() 替代 JSON.parse()
1
2
// 正确写法,指定反序列化类型
User user = JSON.parseObject(result, User.class);
1
2
// 错误写法,依赖 @type 字段实现自动类型识别
User user = (User) JSON.parse(jsonString);
  • (2) 若 Fastjson 使用的是 1.2.83 及之后版本,可以配置全局关闭 safeMode,并配置白名单
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Configuration
public class FastjsonConfig {

@PostConstruct
public void initFastjsonConfig() {
// 全局关闭 safeMode(Fastjson 1.2.68+ 版本生效)
ParserConfig.getGlobalInstance().setSafeMode(false);

// 开启全局 autoType(为了系统安全,建议使用白名单开启 autoType,而不是全局开启)
// ParserConfig.getGlobalInstance().setAutoTypeSupport(true);

// 开启白名单(允许指定类使用 autoType)
ParserConfig.getGlobalInstance().addAccept("com.clay.system.model.User");
ParserConfig.getGlobalInstance().addAccept("com.clay.system.model.Token");

// 开启白名单(允许指定包名及其子包中的类使用 autoType)
// ParserConfig.getGlobalInstance().addAccept("com.clay.system.model.");
}

}
  • (3) 若 Fastjson 使用的是 noneautotype 版本,可以换成正常版本
1
2
3
4
5
6
<!-- 正常版本 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
1
2
3
4
5
6
7
8
<!-- noneautotype 版本 -->
<!--
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83_noneautotype</version>
</dependency>
-->
  • (4) Fastjson 1.x 已经停止维护,若条件允许,推荐升级到 Fastjson2(2.0.x 版本)
1
2
3
4
5
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.34</version>
</dependency>

然后使用 JSON.parseObject() 进行反序列化

1
User user = JSON.parseObject(jsonString, User.class);