反射本身不是漏洞,而是java反序列化攻击链中关键的“执行引擎”,通过动态调用类、方法、字段绕过编译期检查,在readobject等钩子中被滥用实现任意代码执行。

反射本身不是漏洞,但它是Java反序列化攻击链中不可或缺的“执行引擎”。当反序列化过程失去输入控制时,攻击者借助反射动态调用类、方法、字段,绕过编译期检查,把恶意逻辑注入运行时——这才是真正危险的地方。
反射在反序列化链中的关键作用
Java反序列化不直接执行代码,而是重建对象图。但很多类(尤其是第三方库)在反序列化过程中会主动触发反射行为:
-
readObject()、readResolve()、readExternal()等钩子方法被自动调用,若开发者在其中使用
Class.forName()、Method.invoke()或Constructor.newInstance(),就打开了反射入口 - Apache Commons Collections 的
InvokerTransformer就是典型:它不包含恶意代码,但通过反射链式调用Runtime.getRuntime().exec(),实现任意命令执行 - Fastjson 的
autoType开启后,会根据 JSON 中的@type字段通过反射加载并实例化任意类,哪怕该类未在业务代码中显式引用
常见被滥用的反射模式
这些看似合理的开发习惯,恰恰成为攻击载荷落地的温床:
-
动态类加载:如
Class.forName(className)+ 用户可控的className字符串,可加载javax.naming.InitialContext等JNDI类,触发远程类加载 -
无校验的方法调用:如
obj.getClass().getMethod(methodName).invoke(obj),若methodName来自反序列化数据,就可能调用到setDataSourceName、getObjectInstance等敏感方法 - 构造器反射实例化:某些框架为兼容性允许通过反射创建私有/无参构造对象,攻击者可借此绕过正常初始化流程,让恶意静态块或初始化代码提前执行
为什么Spring、Jackson、Fastjson都曾中招
不是它们“用了反射”,而是它们的设计让反射行为与用户输入深度耦合:
-
Spring RMI:
JtaTransactionManager在反序列化时会反射调用lookup()方法,配合可控的 JNDI URL 即可触发远程代码执行 -
Jackson:
enableDefaultTyping()启用后,JSON 中的@class字段会被反射解析为具体类型,若白名单缺失,可指定com.sun.rowset.JdbcRowSetImpl并注入dataSource和autoCommit触发 JNDI 查找 -
Fastjson:1.2.24 版本前默认开启
autoType,且仅靠简单包名黑名单过滤,攻击者用com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl绕过,再结合TransformerFactory反射触发字节码加载
防御思路:切断反射与不可信输入的绑定
核心不是禁用反射,而是阻断“用户输入 → 反射调用”的路径:
- 关闭所有框架的自动类型识别功能:Fastjson 设置
ParserConfig.getGlobalInstance().setAutoTypeSupport(false);Jackson 禁用enableDefaultTyping() - 对反序列化入口做严格白名单:使用
ValidatingObjectInputStream或自定义ObjectInputStream.resolveClass(),只允许已知安全类加载 - 避免在
readObject()等钩子方法中写反射逻辑;若必须使用,确保类名、方法名、参数值全部来自硬编码或配置项,而非反序列化数据本身 - 运行时限制:JVM 启动参数加入
-Djdk.lang.ProcessHandle.disableSystemExit=true和--illegal-access=deny,降低反射滥用后果
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











