Fastjson 反序列化漏洞演进、底层机理
2026/6/28 19:39:55 网站建设 项目流程

Fastjson 是 Java 生态中广泛使用的 JSON 解析库,其反序列化漏洞历经多年迭代仍未彻底根治。本文从防御视角出发,系统梳理 Fastjson 各版本的安全机制演进、机制失效的根本原因、Gadget 类型分类及防御建议,旨在为安全审计与架构设计提供全面参考。

一、 核心防御演进与机制失效路径

Fastjson 的安全演进史,本质上是一场“动态类型推导”与“攻击者 Gadget 挖掘”的博弈过程。

1. 1.2.24 以前:无 AutoType 阶段(完全反射驱动)

核心机制

早期版本采用纯反射驱动的反序列化模型。当使用JSON.parseObject(json, Target.class)或通用的JSON.parse(json)时,Fastjson 会根据 JSON 中的@type键动态加载类。

JSON 字符串 (含 @type) └──> DefaultJSONParser.parse() └──> JavaBeanDeserializer.deserializer() └──> MethodInvoker / FieldDeserializer └──> 反射调用 target.setXxx() / getXxx()
风险本质与防御缺陷
  • 无边界信任@type字段可指定任意类,完全信任输入内容,无类白名单机制。

  • 副作用方法触发:反序列化时会自动触发符合条件的Setter、特定的Getter以及无参构造函数,从而触发“副作用方法”构造利用链。

2. 1.2.25 - 1.2.46:AutoType 初代(黑名单机制)

防御引入

引入checkAutoType(String typeName, Class<?> expectClass, int features)函数,默认关闭AutoType支持。若开启,则配合内置的denyList(黑名单)和acceptList(白名单)实现基础过滤。

架构缺陷一:静态黑名单的天然滞后性

黑名单机制属于消极防御。Java 生态中的第三方组件(如 Spring, Tomcat, Commons-Collections)极其庞大,黑名单永远无法全覆盖。

架构缺陷二:Class 缓存污染(Mapping Cache 绕过)

这是该阶段最经典的架构漏洞。Fastjson 为了提升性能,设计了类加载缓存机制(TypeUtils.mappings)。

[输入类名] ──> checkAutoType() 检查 ──> (不在黑名单) ──> Class.forName() 加载 │ [后续输入] <── 从 mappings 缓存直接返回 <── 注入 mappings 缓存 <──┘

绕过原理:攻击者通过特定的基础类(如java.lang.Class)触发解析,诱导 Fastjson 将恶意类加载并写入mappings缓存。在随后的解析中,恶意类直接跳过checkAutoType检查,从缓存中被直接返回。

3. 1.2.48 - 1.2.68:ExpectClass(期望类型)引入与类型收窄

防御升级

修复了缓存污染漏洞,并引入expectClass参数,实施类型子树收窄约束:

$$\text{if } (\text{clazz} \not\subseteq \text{expectClass}) \longrightarrow \text{REJECT}$$

绕过思路:利用“广泛继承根”(合法接口族)

当业务代码要求反序列化某个接口或基类时(例如JSON.parseObject(json, Serializable.class)),expectClass赋值为该接口。攻击者转向利用实现了这些广泛接口的“合规 Gadget”:

  • java.io.Serializable

  • java.lang.AutoCloseable

  • java.lang.Throwable

失效根本原因:安全边界 $\neq$ 类型边界。expectClass允许的子树范围过大,恶意 Gadget 依然隐藏在合法的子树内部。

4. 1.2.69 - 1.2.80:安全模型收紧与基础设施类滥用

防御演进

不断扩充黑名单,强化expectClass校验,逐步推出SafeMode雏形。

攻击面转向

攻击者不再局限于常规的第三方组件漏洞,转而滥用 JDK 或常用框架的“基础设施类”:

  • 特殊集合类Collection/Queue/Map的特殊实现。

  • 内部工具类:JDK 内部负责代理、动态绑定或特殊上下文切换的类。

共性利用模型:

$$\text{JSON Input} \longrightarrow \text{Object Graph Construction} \longrightarrow \text{Setter/Getter Chain} \longrightarrow \text{Indirect Sink Invocation}$$

5. 1.2.83+ & Fastjson v2:SafeMode 与架构重构

SafeMode 防御原理

全面关闭AutoType功能,不解析任何包含@type的动态类,强制执行严格 Schema 绑定(Strict Schema Mapping)。

Fastjson v2 架构变革
  • 流式解析器(Streaming Parser):重写底层架构,极大降低对反射的依赖。

  • 显式多态注册:废弃全局任意类反序列化,多态类必须通过@JSONType(seeAlso = {...})显式声明。

二、 Gadget 类型分类(防御与审计视角)

从防御视角来看,不论 Gadget 如何变化,其落脚点(Sink)主要分为以下三类:

1. JNDI / 远程资源加载类(远程 Sink)

  • 特征:通过触发Context.lookup()或远程 URL 加载。

  • 典型代表com.sun.rowset.JdbcRowSetImpl

  • 触发链setDataSourceName()$\rightarrow$setAutoCommit()$\rightarrow$InitialContext.lookup(dataSourceName)

2. 本地命令执行型(OS 命令 Sink)

  • 特征:直接或间接调用Runtime.getRuntime().exec()ProcessBuilder

  • 典型代表:各类利用模板类(如TemplatesImpl)加载恶意字节码,或利用脚本引擎(ScriptEngineManager)执行内联代码。

3. 反序列化副作用链(中间桥梁 Sink)

  • 特征:本身不执行命令,但其Setter方法会触发其他引擎的解析。

  • 分类

    • XML 解析引擎(触发 XXE / 远程对象注入)

    • 表达式引擎(触发 SpEL、EL、OGNL 表达式注入)

    • 模板引擎(触发 Velocity、FreeMarker 模版注入)

三、 环境对抗演进

1. JDK 基线演进对漏洞利用的影响

JDK 版本基线默认配置行为攻击面转移阻尼
< JDK 8u121 / 7u131com.sun.jndi.rmi.object.trustURLCodebase=true黄金时代:可通过 RMI 远程加载任意恶意类。
< JDK 8u191 / 7u201com.sun.jndi.ldap.object.trustURLCodebase=trueLDAP 时代:RMI 受阻,转而利用 LDAP 协议绕过。
$\ge$ JDK 8u191远程 Codebase 默认全部关闭本地 Gadget 时代:被迫转向纯本地 Gadget 链组合(如利用BeanFactory触发本地命令执行)。

2. WAF 检测对抗(绕过特征分析)

WAF 通常基于规则匹配,攻击者常用以下机制实施绕过:

  • 编码混淆:利用 Fastjson 支持的字符集,使用 Unicode 编码(如\u0040\u0074\u0079\u0070\u0065代替@type)或十六进制/常规转义。

  • 结构扰动:改变 JSON Key 的顺序,或者插入大量无关的嵌套多层对象包装,冲刷 WAF 的深度扫描限制。

  • 语法兼容路径:利用 Fastjson 独有的解析特性,如用,/{}畸形闭合等非标准 JSON 语法绕过规范的 WAF 解析器。

四、 终极防御建议

依赖黑名单补丁无法从根本上解决 Fastjson 的安全问题,架构设计应转入深度防御模式

1. 强制启用静态 Schema 绑定

  • 拒绝使用通用的JSON.parse(String text)

  • 必须指定明确的 DTO 类:JSON.parseObject(text, UserDTO.class)

  • 禁止在 DTO 中使用ObjectSerializable等宽泛类型作为属性。

2. 开启 SafeMode / 升级 v2

  • Fastjson 1.x:在 JVM 启动参数中显式添加-Dfastjson.parser.safeMode=true,或在代码初始化时执行ParserConfig.getGlobalInstance().setSafeMode(true)

  • Fastjson 2.x:全面向 v2 版本迁移,不开启兼容 1.x 的@type解析模式。

3. 语义级输入规范化与 WAF 联动

  • 解析前规范化(Canonicalization):在 WAF 或网关层对 JSON 进行统一的反转义与解码。

  • AST 语义检测:WAF 层的检测应基于 JSON AST(抽象语法树)结构检查是否存在非预期的键(如@type),而非单纯的字符串正则表达式匹配。

总结:演进历程一览表

阶段核心特征核心缺陷机制根本解决方向
无约束反射时代(< 1.2.24)完全信任输入,由@type反射驱动。无边界约束,任意反序列化。转向静态绑定:放弃“允许动态类型”的架构设计,全面转向强类型 Schema 绑定SafeMode,方能从根源阻断反序列化攻击面。
黑名单补丁时代(1.2.25 - 1.2.46)引入checkAutoType,依赖静态黑名单 + 缓存。黑名单不完备,缓存污染(Mapping 绕过)。~
类型约束与安全模式时代(1.2.48+)引入expectClass限制类型树,逐步推行SafeMode类型约束过宽(合法接口族绕过),残留语法兼容路径。~

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询