核心是识别“不受控的动态行为”:核查反射目标是否来自不可信输入、是否滥用setaccessible(true)、是否绕过权限校验、是否有运行时防护与可观测性,四类风险缺一不可。

在代码评审中评估 Java 反射机制的安全风险,核心是识别“不受控的动态行为”——即那些由外部输入驱动、绕过编译期检查、且未施加访问约束的反射调用。它不在于“用了反射”,而在于“谁控制了反射的目标与行为”。以下四类关键点需逐项核查:
一看:反射目标是否来自不可信输入
这是最高危场景。若 Class.forName()、getDeclaredMethod() 或 getDeclaredField() 的参数(如类名、方法名、字段名)直接来源于 HTTP 请求参数、配置文件、数据库读取值或用户提交内容,就构成典型的反射注入入口。
- 危险示例:
String className = request.getParameter("type"); Class> clazz = Class.forName(className); - 评审动作:搜索
getParameter、getHeader、getProperty、readLine等输入源后紧跟Class.forName或getDeclaredXXX的组合 - 安全替代:使用白名单枚举映射(如
Map<string class></string>),或通过接口+工厂模式解耦类型选择逻辑
二查:是否滥用 setAccessible(true)
该调用等同于临时关闭 JVM 访问控制闸门。评审时需确认其必要性与作用域:
- 是否仅用于框架必需场景(如 Jackson 反序列化私有字段)?还是出现在业务逻辑层?
- 是否对所有反射获取的成员无差别调用?应限定为明确需要访问的特定字段/方法,而非批量
setAccessible(true) - Java 9+ 项目是否已通过
--add-opens显式开放模块?未配置却强行调用会抛InaccessibleObjectException
三审:反射调用是否绕过权限校验
尤其关注反射调用是否发生在鉴权之后、业务逻辑执行之前。例如:
- 用户已通过 RBAC 鉴权,但反射调用的方法内部又执行了更高权限操作(如
Runtime.exec、System.setProperty) - 反序列化入口(如
ObjectInputStream.readObject())未启用ObjectInputFilter,导致攻击者可构造含恶意反射链的 gadget 类 - 评审动作:标记所有反射调用点,回溯其上下文是否已做完整权限判断;检查是否遗漏
SecurityManager检查(虽已弃用,但遗留系统仍需关注)
四验:是否有运行时防护与可观测性
静态评审不能替代运行时防御。需确认是否部署了纵深防护措施:
- 是否启用 JVM 全局反射限制?如 Java 17+ 默认启用
--illegal-access=deny,禁止非法跨模块反射 - 是否在关键反射路径添加日志审计?例如记录调用方类、目标类名、方法签名、调用时间(注意脱敏敏感字段值)
- 是否集成 SAST 工具(如 Checkmarx、SonarQube)扫描反射高危模式?重点规则包括:
Class.forName + untrusted input、setAccessible(true) outside framework packages
反射本身不是漏洞,失控的反射才是。代码评审要抓准“输入来源—访问控制—执行上下文—运行时约束”这条链,把每一次 getDeclared 和 invoke 都当作一次潜在的权限跃迁来对待。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











