AutoType 安全与修复建议

Fastjson 是一个高性能的 JSON 处理库,但它的 AutoType 功能(自动类型识别)曾引发严重的安全问题。本文将解释 AutoType 的原理、风险,并提供修复建议。

什么是 AutoType?

AutoType 是 Fastjson 的一个特性:在反序列化时,无需显式指定要转换的 Java 类型,而是根据 JSON 中的 @type 字段自动识别并创建实例

// JSON 字符串中包含 @type 字段
String json = "{\"@type\":\"com.example.User\",\"name\":\"Alice\",\"id\":1}";

// 可以直接反序列化为 User 对象
Object obj = JSON.parse(json);  // 默认启用 AutoType 时,会识别 @type

AutoType 的安全风险

AutoType 最大的问题是 可能导致远程代码执行(RCE)。攻击者可以通过构造特殊的 JSON 字符串,让 Fastjson 反序列化时调用危险方法,例如:

{
  "@type": "java.net.InetAddress",
  "val": "malicious-server.com"
}

更严重的例子是结合某些 Java 库(如 fastjson 的 AutoType 白名单绕过)执行任意命令。历史上多个 Fastjson 版本因此被爆出高危漏洞(如 CVE-2022-25845)。

核心问题:Attackers 可以通过 @type 指定任意类的构造函数或 setter,如果该类在类路径中且包含不安全逻辑,则能实现攻击。

安全修复建议

禁用 AutoType(最推荐)

在 JSON.parse / parseObject 时显式指定目标类型,避免使用 @type

// 安全方式:指定目标类型
String json = "{\"name\":\"Alice\",\"id\":1}";
User user = JSON.parseObject(json, User.class);  // 不依赖 @type

如果必须使用 JSON.parse(String),可以通过配置全局禁用 AutoType:

ParserConfig.getGlobalInstance().setAutoTypeSupport(false); // 禁用自动类型

白名单模式(如必须 AutoType)

如果业务需要 AutoType,只允许特定的安全类。

ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
ParserConfig.getGlobalInstance().addAccept("com.example.myapp."); // 只接受该包下的类

或者使用安全黑名单方式(不推荐,因为攻击者总能寻找新类):

ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
// 建议使用白名单,而不是黑名单

升级到最新版本

快速修复漏洞的最佳方法是升级到 Fastjson 的最新安全版本(目前建议 >= 1.2.83)。例如:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.83</version> <!-- 检查最新版本 -->
</dependency>

最新版本通常已修复已知的 AutoType 漏洞。

使用替代库

如果业务对安全要求极高,可以迁移到更安全的 JSON 库,如 Jackson(需正确配置)或 Gson(默认不开启自动类型识别)。

实际修复示例

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;

public class SafeFastjsonDemo {
    public static void main(String[] args) {
        // 方案一:禁用 AutoType
        ParserConfig.getGlobalInstance().setAutoTypeSupport(false);

        // 方案二:使用白名单(假设业务需要)
        // ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        // ParserConfig.getGlobalInstance().addAccept("com.example");

        // 安全的反序列化:指定类型
        String userJson = "{\"name\":\"Tom\",\"age\":25}";
        User user = JSON.parseObject(userJson, User.class);
        System.out.println(user.getName());

        // 永远不要使用未校验的 JSON.parse(String) 且不指定类型
        // 例如:Object obj = JSON.parse(userJson);  // 危险!
    }
}

总结

作为开发者,你的首要任务是禁用或严格限制 AutoType 的使用。结合升级库版本和代码审查,可以极大降低安全风险,反序列化时永远不要信任外部输入。