You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SecurityManager弃用后,如何通过Java反射实现反序列化器白名单?

用Java模块系统替代SecurityManager控制suppressAccessChecks权限

在Java 9+中,废弃SecurityManager后,模块系统确实是替代它实现suppressAccessChecks权限白名单控制的最佳方案,以下是具体实现步骤和思路:

1. 模块声明层面的权限控制(核心)

通过module-info.java的静态声明,可以精准指定哪些模块能获得suppressAccessChecks权限,无需动态代码检查。

假设你的反序列化器模块是com.example.deserializer,被反射操作的目标模块是com.example.target,在目标模块的module-info.java中添加:

module com.example.target {
    // 仅允许白名单模块访问目标内部类(可选,配合反射使用)
    opens com.example.target.internal to com.example.deserializer;
    
    // 直接授予白名单模块suppressAccessChecks权限
    grants java.lang.reflect.ReflectPermission "suppressAccessChecks" to com.example.deserializer;
}

grants语句是模块系统专门用于权限授予的语法,只有指定的模块能获取该反射权限,其他模块调用时会直接抛出SecurityException。

2. 代码层面的动态白名单校验(可选增强)

如果需要像之前那样做动态调用者校验,用Java 9引入的StackWalker替代StackTraceElement,能更高效地获取调用者的模块信息:

public void validateSuppressAccessCaller() {
    // 获取调用者的类与模块信息
    StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
    Module callerModule = walker.getCallerClass().getModule();
    
    // 定义白名单模块
    Set<String> allowedModules = Set.of("com.example.deserializer");
    
    if (!allowedModules.contains(callerModule.getName())) {
        throw new SecurityException("模块[" + callerModule.getName() + "]无权限调用suppressAccessChecks");
    }
}

在需要调用suppressAccessChecks的代码前,先执行这个校验方法即可。

3. 运行时参数的动态调整(教学演示用)

在教学演示时,可以用JVM参数快速切换权限规则,展示不同场景的效果:

  • 临时允许某个模块访问:--add-opens com.example.target/internal=com.example.deserializer
  • 临时授予权限:--add-grants java.base/java.lang.reflect=com.example.deserializer
  • 拒绝所有非白名单模块:无需额外参数,模块系统会默认拦截未授权的调用

模块系统方案的优势

  • 更可靠:静态声明的权限由JVM强制校验,很难被绕过,比SecurityManager的动态代码检查更安全。
  • 粒度更细:可以针对特定包、类甚至单个权限做精确控制,而非全局的权限拦截。
  • 性能更高:模块系统的权限检查是JVM层面优化的,比遍历堆栈的开销小很多。

内容的提问来源于stack exchange,提问作者Marco Servetto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 02:00:34