/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}
老炮踩坑录 · S01 · 跨项目联动系列 基于六个真实项目的仓库的 fastjson 依赖实扫,版本、声明写法、漏洞区间逐条附行号 关键词:FastJSON · autoType · 依赖版本管理 · 1.2.76 · safeMode
👋 欢迎阅读

🏠个人主页: 知守观 📘我的专栏: 老炮踩坑录 💻当前内容:FastJSON 巡检记
文章目录
-
- 引言
- 先把 fastjson 的版本线记清楚
- 三个项目都是 1.2.83,声明写法却各不相同
- 企业资产管理停在 1.2.76,正好躺在 1.2.80 的漏洞区间里
- 一个仓库三个版本:1.2.15、1.2.60、1.2.79
- 最老的项目没有这个坑
- 六个仓库,没有一个开过 safeMode
- 整改对照表
- 老炮点评
引言
上一篇合集写完密钥入库,有个读者留言问:你说的这些仓库,fastjson 都是什么版本?
这个问题把我问住了。我手边同时维护过好几个项目,fastjson 每个项目都在用,但哪个项目用的哪个版本,我一个都答不上来。离职以后仓库都在本地,我花了整整一个下午把六个仓库的构建文件全翻了一遍。
结果比预想的难看。四个项目在 1.2.83,一个在 1.2.76,最老的那个 2014 年的 P2P 网关反而一个 fastjson 都没有。同样一个依赖,六种处境。这篇文章按项目逐个分析,行号都是我在本地仓库核实过的,最后给一张整改对照表。
先把 fastjson 的版本线记清楚
巡检之前得先有个判断标准,不然光看版本号看不出好坏。fastjson 的问题集中在 autoType 反序列化上,公开的时间线大致是这样:
2017 年,第一个 autoType 反序列化漏洞公开,影响 1.2.24 及以下版本。1.2.25 起官方默认关闭 autoType,并引入黑名单校验。之后几年是黑名单和绕过的循环,1.2.41、1.2.42、1.2.43、1.2.45 陆续出绕过,2019 年 1.2.47 那次利用缓存机制的绕过影响面最大,基本波及当时所有在网版本。
2020 年 1.2.68 引入 safeMode,开启后彻底禁用 autoType,算是给了一个一刀切的选择。
2022 年 5 月,1.2.80 及以下版本又被发现新的绕过,1.2.83 修复。
具体的版本区间和漏洞编号,以 fastjson 官方安全公告为准,我这里只按公开资料整理出四条判断线:
- 1.2.24 及以下:2017 年那波老漏洞的影响范围
- 1.2.25 到 1.2.46:黑名单时期,陆续有被公开的绕过
- 1.2.47 到 1.2.80:包含 1.2.47 缓存绕过和 2022 年那次新绕过的影响范围
- 1.2.83:最近一次公开漏洞的修复版本,也是 1.x 线的收尾版本
四条判断线有了,下面逐个项目核对。
三个项目都是 1.2.83,声明写法却各不相同
基础档案、商品中台、促销,这三个项目的版本号一样,都是 1.2.83。但版本写在哪儿、怎么写,三家三个写法。
- 基础档案,写在公共模块的 pom 里硬编码,pom.xml 第 39 到 43 行:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
根 POM 里没有任何 fastjson 相关的 properties 或依赖管理。全项目代码里 import fastjson 的只有 6 个文件 8 处,用得最重的反而是 Cons.java 里一组序列化特性开关。使用这么轻,升版本成本很低,这是好事。
- 促销系统,promotion-api/pom.xml 第 47 到 52 行:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
<scope>compile</scope>
</dependency>
也是硬编码,还多带了一个显式的 scope compile。全仓库 grep 下来,促销系统只有这一处声明 fastjson。也就是说,整个促销系统所有模块的 fastjson 版本,由 api 模块这一个 pom 说了算,其他模块全是从这里传递依赖拿到的。版本决策点藏在一个业务模块里,不在根 POM,下次升级的时候,改的人得先找到这个决策点在哪。
- 商品中台最典型,一个仓库里两种写法并存。pom.xml 第 27 行定义了属性:
<fastjson.version>1.2.83</fastjson.version>
公共模块引用这个属性。同一个仓库的 api/pom.xml 第 42 到 46 行,却把 1.2.83 又硬编码了一遍,不走属性:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
今天两个写法指向同一个数字,相安无事。哪天有人把属性改成 1.2.85,api 纹丝不动,同一个系统里两个模块各用各的版本,类路径上谁先加载看谁排在前面。商品中台是用 fastjson 最深的项目,100 个文件 137 处 import,真出一次版本不一致,排查量不小。
三个项目版本号一样,属于巧合,不属于治理。没有任何一个机制保证它们停在同一个版本,只是 2022 年那波漏洞通报的时候,各项目组各自升了一轮,碰巧都升到了当时最新的 1.2.83。
企业资产管理停在 1.2.76,正好躺在 1.2.80 的漏洞区间里
企业资产管理系统,pom.xml 第 34 行:
<fastjson.version>1.2.76</fastjson.version>
声明写法反而是几个项目里最规矩的:属性定义、dependencyManagement 统一管理、子模块引用,一套是齐的。问题只在数字上。1.2.76 小于 1.2.80,2022 年公开的那次 autoType 绕过正好覆盖它。
这个项目 fastjson 用得一点不轻,56 个文件 80 处 import,控制器、服务、定时任务、Feign 客户端全在用。用得多,版本旧,组合起来就是六个仓库里最敞亮的一个风险敞口。
为什么它没跟着升到 1.2.83?我没法替当时的团队回答,项目记录里也没有。从时间上看,1.2.83 是 2022 年 5 月发的,企业资产管理系统这个版本号大概定在那之前,后来没有触发升级的事件,就一直停在原地。漏洞通报这类事,没人盯着依赖清单,就不会有人知道自己在影响范围里。
一个仓库三个版本:1.2.15、1.2.60、1.2.79
同一个仓库,grep 一遍 pom.xml,fastjson 出来三个版本:
xueYiShop-common/pom.xml: 1.2.15
renren-generator/pom.xml: 1.2.60
renren-fast/pom.xml: 1.2.79
挨个看。renren-generator 是代码生成器工具,1.2.60,落在黑名单被反复绕过的时期。renren-fast 是后台管理脚手架,1.2.79,落在 2022 年那次绕过的影响范围里。这两个好歹是独立模块,影响面有限。
最狠的是 xueYiShop-common,第 53 到 57 行硬编码 1.2.15:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.15</version>
</dependency>
1.2.15 是 2016 年前后的版本,比 2017 年第一个公开的 autoType 漏洞还早,稳稳在 1.2.24 的影响范围里。而 xueYiShop-common 按它的模块说明是 “每一个微服务公共的依赖”,订单、商品、库存、会员、秒杀,12 个业务模块全部依赖它。一个仓库里最老的版本,被最广泛地共享。
同样的结构搬进真实项目的人不少:公共模块钉一个老版本,全系统跟着用,单点决策,全局生效。
最老的项目没有这个坑
P2P 网关,2014 年的技术栈,Spring 3.2.8、Struts 2.3.16.3。我把它的 build.gradle 和本地 lib 目录翻了个底朝天,fastjson 一个都没有。它处理 JSON 用的是这些:
common/lib/json/json-lib-2.2.2-jdk13.jar
common/lib/json/json-lib-2.2-jdk15.jar
common/lib/json/ezmorph-1.0.5.jar
common/lib/jodconverter/json-20090211.jar
json-lib 加 ezmorph,org.json 的版本号直接是日期。这套东西老得连 autoType 这个概念都不存在,自然也没有这个系列的漏洞。
说它没有这个坑,不等于它安全。Struts 2.3.16.3 和 Shiro 1.2.3 的攻击面是另一个话题,这里不展开。只说 fastjson 这一件事:它躲过这十年的唯一原因,是它老到没赶上。
六个仓库,没有一个开过 safeMode
版本号之外,我还扫了一遍代码里的加固动作。1.2.68 以后官方给了 safeMode,开启后 autoType 彻底禁用,不用赌黑名单有没有漏。开启方式一行代码或者一个 JVM 参数:
ParserConfig.getGlobalInstance().setSafeMode(true);
六个仓库,我按 ParserConfig、autoType、safeMode 三个关键词全量扫 Java 源码,命中数是零。没有任何一个项目做过这件事。大家做的唯一动作就是升版本,升完就完。
这个发现比版本旧更让我在意。升版本是被动响应,漏洞通报了才动。开 safeMode 是主动防御,不依赖"我的版本当前没有公开绕过"这个假设——这个假设在 fastjson 的十年历史里被推翻了太多次。
整改对照表
有个细节我没完全确认:我这次只核到了模块 pom 里显式声明的部分,没有逐项目跑 mvn dependency:tree 看最终解析结果。如果你要照这张表整改,动手前自己跑一遍依赖树确认最终生效版本。
自查打卡:在你的仓库根目录跑一句:grep -rn -A1 “fastjson” –include=pom.xml . | grep version 看看跳出来几个数字、几种写法? 另外,全局搜一下 setSafeMode(true) 或者 -Dfastjson.parser.safeMode=true,看看有没有命中。 打在评论区,我看看谁的仓库最原生态。
老炮点评
这轮巡检最让我意外的不是 1.2.76,是三个 1.2.83 的巧合。没有任何机制把它们钉在同一个版本,只是同一次漏洞通报让几个项目组同时动了手。这意味着下一次 fastjson 再出公告,同样的过程会重来一遍:各项目组各自升级,有的升有的忘,忘掉的那个项目就停在漏洞区间里。
漏洞通报这种事件驱动的升级,撑不起一个要用十年的项目群。能落地的机制其实不贵:根 POM 里统一定义版本属性,CI 里加一步依赖版本一致性检查,再狠一点把 safeMode 或 JVM 参数 -Dfastjson.parser.safeMode=true 写进部署模板。三件事加起来半天工作量,后面再出公告,就不用每个项目组各自判断一遍自己有没有漏。
再往深说一句,fastjson 这十年的问题是结构性的:autoType 的设计目标和安全模型天然冲突,黑名单永远慢绕过一步。1.2.83 是当前修复线,不是终点。新项目不建议再入这个坑,存量项目评估迁移 Jackson 或者 fastjson2 的成本,比等下一次通报强。
最后问一句:你现在维护的系统,FastJSON 是什么版本?如果明天官方再爆一个新漏洞,你们公司是有一套统一的依赖升级机制,还是只能靠开发自己去各个 pom 里“排雷”?评论区聊聊。
如果本文对你有帮助,欢迎:
👍 点赞 | ⭐ 收藏 | 👤 关注 | 💬 留言
欢迎留言探讨。你的每一次互动,都是我继续更新的动力🚀
下期预告:《分布式锁四家对照:croods 锁、Redisson、手写 Locker、事件兜底》
跨项目联动继续。同一家公司的四个项目,分布式锁用出四种写法:企业资产管理按资产卡片号加锁、学逸商城 Redisson 全家桶、促销自己封装 Locker、供应链走事件兜底。同一个问题四种答案,各自的问题逐条核对。
我是老炮,18 年 Java 老兵,仍在一线。关注我的 CSDN 专栏「老炮踩坑录」,真实项目复盘,让你少走弯路。

