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

Java 18及以上版本创建无需已弃用SecurityManager的RMI程序及替代方案

RMI程序中SecurityManager弃用后的替代方案

因为SecurityManager以及配套的AccessController在Java 18之后被弃用,原来用来控制RMI远程代码下载的安全机制得换思路。目前主要靠Java模块系统、自定义类加载器和RMI内置的代码源限制来实现安全管控,核心原则就是最小权限,尽量避免加载不可信的远程代码。

具体实现方案

1. 直接禁用远程代码下载(首选最安全)

如果你的RMI应用根本不需要从远程服务器加载类,直接把这个功能关掉就行,从根源杜绝风险。

  • 启动JVM时加参数:
java -Djava.rmi.server.useCodebaseOnly=true
  • 或者在代码里提前设置:
System.setProperty("java.rmi.server.useCodebaseOnly", "true");

这个参数会强制RMI只从本地类路径加载类,完全拒绝任何远程代码源的请求,绝大多数场景都适用。

2. 用Java模块系统锁死类访问权限

通过module-info.java定义模块化结构,严格控制模块之间的访问权限,防止远程加载的类碰敏感API:

  • 只导出RMI服务必须对外暴露的包
  • 限制远程类所在模块的权限,不让它访问java.base里的敏感功能

示例module-info.java:

module com.example.rmi.server {
    // 只对外导出RMI服务接口的包
    exports com.example.rmi.service;
    // 只允许RMI核心模块访问内部实现
    opens com.example.rmi.impl to java.rmi;
    // 依赖RMI核心模块
    requires java.rmi;
}

3. 自定义类加载器验证代码源

如果确实需要从远程加载类,自己写个类加载器,加载前先验证代码源是否可信——比如检查是不是来自你预先指定的服务器,或者校验类文件的数字签名:

public class TrustedRMIClassLoader extends URLClassLoader {
    // 预先配置的可信代码源地址
    private static final Set<String> TRUSTED_CODEBASES = Set.of(
        "https://your-trusted-server.com/rmi-classes/"
    );

    public TrustedRMIClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        // 先检查本地是否已加载过该类
        Class<?> loadedClass = findLoadedClass(name);
        if (loadedClass != null) {
            return loadedClass;
        }

        // 校验所有代码源是否在可信列表里
        for (URL url : getURLs()) {
            if (!TRUSTED_CODEBASES.contains(url.toString())) {
                throw new SecurityException("拒绝加载不可信代码源的类:" + url);
            }
        }

        // 调用父类方法加载类
        return super.loadClass(name, resolve);
    }
}

然后在RMI客户端或服务器设置这个类加载器:

// 指定远程代码源地址
System.setProperty("java.rmi.server.codebase", "https://your-trusted-server.com/rmi-classes/");
// 设置上下文类加载器为自定义的可信加载器
ClassLoader parentLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(new TrustedRMIClassLoader(new URL[0], parentLoader));

4. 用细粒度权限控制替代SecurityManager

虽然SecurityManager没了,但可以用java.security.Permissions和ProtectionDomain给远程加载的类分配最小权限,避免它做超出范围的操作:

@Override
protected Class<?> defineClass(String name, byte[] b, int off, int len, CodeSource cs) {
    // 定义仅允许必要操作的权限集合
    Permissions permissions = new Permissions();
    // 比如只允许读取特定系统属性
    permissions.add(new PropertyPermission("java.version", "read"));
    // 创建保护域,绑定权限和代码源
    ProtectionDomain domain = new ProtectionDomain(cs, permissions);
    // 用这个保护域来定义类
    return defineClass(name, b, off, len, domain);
}

注意事项

  • 优先选禁用远程代码下载,这是最省心也最安全的方案,大部分RMI应用其实都不需要远程加载类
  • 要是必须远程加载,一定要严格校验代码源的可信度,最好给类文件加数字签名,防止被篡改
  • 永远遵循最小权限原则,别给远程加载的类多余的权限

内容的提问来源于stack exchange,提问作者Tel lui

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 13:20:33