跳转到帖子

背景前段时间在做一批历史系统的安全巡检时,遇到一类比较典型的告警:网关日志里出现了带有 @type 字段的 JSON 请求,目标接口本身是一个业务查询接口,不应该接收复杂对象。结合依赖清单发现,该系统仍在使用较老版本的 Fastjson。这个场景在存量 Java Web 系统里并不少见,尤其是多年未升级的后台管理系统、内部接口网关和数据同步服务。这篇文章不讨论利用链细节,也不提供攻击载荷,重点放在如何在授权环境下判断风险、定位代码入口、复现安全影响,以及最终如何加固。反序列化问题的坑点在于:很多时候漏洞不在某一个明显的控制器里,而是在框架封装、通用解析工具类、消息消费逻辑中被反复调用。问题场景这次排查的系统大致有几个特点:Java 8,Spring MVC 架构,部分模块较老。依赖中存在 Fastjson 1.2.x 早期版本。项目里大量使用 JSON.parseObject、JSON.parse 处理外部输入。部分接口直接接收 String body,再手动转换为对象。网关日志中出现异常 JSON 字段,如 @type、不符合业务字段的嵌套对象。这里需要注意一点:日志中出现类似字段不等于一定被利用成功。它只能说明有人或扫描器尝试触发相关行为。真正要判断风险,需要结合版本、配置、调用方式、类路径依赖和实际执行效果。技术分析Fastjson 的历史风险主要来自反序列化过程中对类型信息的处理。当解析输入中包含类型标识时,库可能会尝试根据该类型创建对象。如果项目 classpath 中存在某些危险类,且版本或配置允许自动类型解析,就可能引发安全问题。实际审计时,我一般从三个层面判断:依赖层:确认 Fastjson 版本、是否存在多个版本冲突、是否通过传递依赖引入。代码层:确认是否对外部输入使用了通用解析方法,尤其是未指定目标类型的解析。运行层:确认 AutoType、安全模式、白名单/黑名单配置,以及接口是否真的可达。常见的高风险写法包括:Object obj = JSON.parse(input);

JSONObject jsonObject = JSON.parseObject(requestBody);

Map<String, Object> map = JSON.parseObject(requestBody, Map.class);并不是说这些写法必然可利用,但如果输入完全来自 HTTP 请求、MQ 消息、外部回调,并且没有字段校验,就需要重点关注。相对更安全的做法是指定明确 DTO,并对字段做约束:UserQueryDTO dto = JSON.parseObject(requestBody, UserQueryDTO.class);

// 后续再做字段白名单校验、长度限制、枚举校验等如果业务允许,建议直接使用 Spring 的参数绑定能力,并配合校验注解,减少手动解析不可信 JSON 的机会。关键步骤1. 梳理依赖版本先确认项目实际运行时使用的是哪个版本,不要只看源码里的一个 pom.xml。多模块项目、老项目经常存在依赖覆盖或传递依赖问题。mvn dependency:tree | grep fastjson如果是 Gradle 项目,可以使用:gradle dependencies | grep fastjson如果已经拿到部署包,也建议直接检查:jar tf app.jar | grep -i fastjson

find ./WEB-INF/lib -iname '*fastjson*'这一步的目标是确认真实依赖版本,以及是否存在多个 Fastjson jar 同时出现。多个版本同时存在时,需要进一步确认 classloader 实际加载的是哪一个。2. 定位解析入口代码审计时可以先做粗粒度搜索:grep -R \"JSON.parse\" -n src/
grep -R \"parseObject\" -n src/
grep -R \"Feature.SupportAutoType\" -n src/
grep -R \"ParserConfig\" -n src/重点看以下几类位置:Controller 中接收 String、Map、JSONObject 的接口。通用工具类,例如 JsonUtil、RequestUtil、MessageConverter。MQ 消费者、任务调度回调、Webhook 接收接口。网关、日志、审计相关模块中对请求体的二次解析。很多漏洞并不是在业务接口第一层触发,而是请求进入系统后,被通用组件再次解析。比如某些日志组件为了提取字段,会把原始 body 解析成 JSONObject,这个路径往往容易被忽略。3. 做安全复现而不是盲目打载荷在授权测试环境里,建议先做“无害验证”。例如构造只包含业务字段和异常类型字段的请求,观察服务端是否报错、是否出现 AutoType 相关异常、是否进入对应解析分支。可以关注日志中是否出现类似信息:autoType is not support
syntax error
expect ':' at ...
com.alibaba.fastjson.JSONException如果出现 AutoType 相关异常,说明输入已经走到了 Fastjson 的类型解析逻辑,但是否能造成实际影响还要继续结合版本和配置判断。生产环境不建议直接发送公开利用载荷,更不应尝试执行命令、外连探测或影响业务状态的验证方式。4. 检查全局配置老项目里经常能看到类似配置:ParserConfig.getGlobalInstance().setAutoTypeSupport(true);如果存在这种配置,需要高度关注。很多团队当年为了兼容复杂对象传输打开了 AutoType,后来没有再关闭。更稳妥的方式是禁用全局 AutoType,改成明确类型反序列化,并从业务设计上避免客户端传入任意类型信息。如果确实存在多态反序列化需求,也应该限制在服务端可控范围内,例如使用固定 DTO、枚举 type 字段加手动分发,而不是让 JSON 库根据输入决定实例化哪个类。加固建议这类问题的修复不要只停留在“升级版本”四个字上。升级是必要动作,但不是唯一动作。建议按下面顺序处理。升级依赖:升级到官方维护版本或迁移到更安全的 JSON 处理方案,并确认没有旧版本残留。禁用 AutoType:避免全局开启自动类型识别,不允许客户端提交任意类型信息。明确 DTO:对外接口不要直接接收 Object、JSONObject、裸 Map 作为核心业务入参。字段校验:对字符串长度、数组大小、枚举范围、嵌套层级进行限制。入口收敛:统一 JSON 解析入口,避免各模块各写一套解析逻辑。日志监控:对 @type、异常嵌套对象、解析异常突增做告警。一个比较实用的加固方向是把解析逻辑封装在统一工具中,默认禁止宽泛解析:public final class SafeJson {

private SafeJson() {}

public static <T> T parse(String text, Class<T> clazz) {
if (text == null || text.length() > 1024 * 1024) {
throw new IllegalArgumentException(\"invalid json length\");
}
return JSON.parseObject(text, clazz);
}
}这段代码并不能单独解决所有问题,但它体现了两个原则:解析目标类型必须明确,输入大小需要有边界。实际项目里还应该配合 Bean Validation 做字段级校验。日志与检测思路在事件复盘中,日志非常关键。可以从网关、应用访问日志、异常日志三个方向交叉验证。简单的日志检索可以先关注:grep -R \"@type\" /data/logs/
grep -R \"autoType is not support\" /data/logs/
grep -R \"fastjson\" /data/logs/
grep -R \"JSONException\" /data/logs/如果有集中日志平台,可以按以下维度做聚合:同一源 IP 是否对多个接口发送异常 JSON。异常请求是否集中在老系统或管理后台。请求体中是否存在非业务字段。是否伴随 500 错误、解析异常、线程阻塞或异常外联。这里不建议只依赖单个关键词。部分扫描器会变形字段或压缩请求体,应用日志也可能没有完整记录 body。更可靠的方法是结合 WAF 命中、应用异常、接口路径、时间窗口做关联分析。容易忽略的点内部接口不等于安全:很多反序列化入口存在于内网服务、MQ 消费者、定时任务回调中,一旦边界被突破,风险仍然存在。升级后要确认部署包:构建缓存、私服依赖、旧 jar 残留都可能导致修复未生效。不要只修 Controller:工具类、过滤器、拦截器、日志组件中的解析同样重要。关注异常处理:解析异常如果直接返回堆栈,会暴露版本、类名、包名等信息,方便进一步探测。测试环境要隔离:漏洞验证应在授权环境完成,避免对生产系统造成影响。总结Fastjson 反序列化问题的排查,本质上不是简单看一个版本号,而是要把“外部输入能否进入危险解析路径”这件事讲清楚。实际工作中,我更建议按依赖、入口、配置、运行日志四条线并行推进:先确认真实版本,再定位解析点,然后用无害方式验证输入是否可达,最后结合日志判断是否存在被扫描或利用的迹象。对于长期维护的系统,最有价值的改动是减少宽泛反序列化的使用,把 JSON 解析收敛到明确 DTO 和统一校验流程里。这样即使以后出现新的库漏洞,也能把暴露面控制在较小范围内。

代码审计与漏洞定位示意图
代码审计、调用链与关键函数定位示意

0篇意见

推荐意见

没有意见。

游客
抱歉,你的帖子内容包括我们不允许的字词。请编辑你的帖子,删除下面高亮的屏蔽字。
添加意见…