java - 如何检查 SecurityManager 中的调用者类来源?

标签 java java-security java-security-manager

我有一个用于受信任应用程序代码的 ClassLoader 和一个用于用户提交(不受信任)代码的单独 ClassLoader。

我希望安全管理器限制用户提交的代码。如何从 SecurityManager 中检查调用方来源?查看伪代码:

System.setSecurityManager(new SecurityManager() {
    public void checkPermission(Permission permission) {
        if (/*caller class is not loaded by the trusted classloader*/) {
            throw new SecurityException("You do not have permissions.");
        }
    }
});

我已经尝试过的:

  • StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).getCallerClass().getClassLoader() 首先检查权限,因此它会给出堆栈溢出异常。

  • Thread.currentThread().getStackTrace()[2].getClassLoaderName() 是不安全的,因为它只提供类加载器名称而不是类对象,如果不受信任的加载器的规范名称是与受信任的加载程序相同,这是一个安全问题。

最佳答案

首先,SecurityManager 有一个 protected 方法 getClassContext() .
您的代码将如下所示:

System.setSecurityManager(new SecurityManager() {
    public void checkPermission(Permission permission) {
        Class<?> caller = getClassContext()[1];
        ClassLoader ccl = caller.getClassLoader();
        if (ccl != null || ccl != getClass().getClassLoader()) {
            throw new SecurityException("You do not have permissions.");
        }
    }
});

其次,如果你想使用StackWalker,建议你复用StackWalker实例:

StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
System.setSecurityManager(new SecurityManager() {
    public void checkPermission(Permission permission) {
        Class<?> caller = walker.getCallerClass();
        ClassLoader ccl = caller.getClassLoader();
        if (ccl != null || ccl != getClass().getClassLoader()) {
            throw new SecurityException("You do not have permissions.");
        }
    }
});

第三,这很可能不会如您所愿。安全检查在整个 JDK 中完成,因此调用者可能在任意数量的堆栈级别之外,需要您检查整个堆栈(提示:在您第二次访问堆栈中的 SecurityManager 时中断)。


相反,定义一个策略(创建一个 java 策略文件),您可以在其中授予您的代码所有权限并使用 java.lang.SecurityManager。

如果无法编写您自己的策略文件,您还可以使用 Policy.setPolicy() 来安装您自己的 java.security.Policy 实现。

实现 java.security.Policy 的一些提示:

  • 覆盖implies 和两个getPermissions 方法。说真的。
  • 捕获您自己的 Policy 类的 ProtectionDomain。 (private static final ProtectionDomain MY_PD = MyPolicy.class.getProtectionDomain())
  • 如果检查是针对您自己的 ProtectionDomain,请使用快速路径。在这种情况下不要调用其他代码,否则您可能会遇到 StackOverflow。

关于java - 如何检查 SecurityManager 中的调用者类来源?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57579010/

相关文章:

java - 使用预定义布局在 Android 中以编程方式添加 View

java - 根据两个键值从 Firebase 数据库获取值

java - Guice - 绑定(bind)由辅助注入(inject)工厂创建的实例

java - SSLHandshakeException 导致连接 JMX 时出错

java - 如何防止 Java 代理中定义的 Lambda 表达式破坏其所附加的应用程序?

java - CAS 服务器 Tomcat 8 Java 8 高可用性(HA/集群)

java - 使用 bouncycaSTLe api 创建签名。键始终为空

java - 尝试使用 Java 连接 https 服务器时抛出 SSLHandshakeException

java - JVM - Java 虚拟机损坏

java - 在 checkPermission 方法中加载某些类时,为什么 SecurityManager 会发出递归更新异常?