Java设置已创建实例的安全权限

Java设置已创建实例的安全权限,java,permissions,securitymanager,Java,Permissions,Securitymanager,我有一段代码,它创建了一个类的实例 Class<?> c = Class.forName("MyClass"); Constructor<?> cons = c.getConstructor(); cons.setAccessible(true); Object instance = cons.newInstance(); 我想为(实例的)这段代码设置限制。因此,从该isntance调用的方法不能做可疑的事情(系统调用、文件操作…) 我曾尝试设置安全管理器,但这限制了所

我有一段代码,它创建了一个类的实例

Class<?> c = Class.forName("MyClass");
Constructor<?> cons = c.getConstructor();
cons.setAccessible(true);
Object instance = cons.newInstance();
我想为(实例的)这段代码设置限制。因此,从该isntance调用的方法不能做可疑的事情(系统调用、文件操作…)

我曾尝试设置安全管理器,但这限制了所有代码(我仍然希望在其余代码中读取/写入文件)。 是否可以仅限制某些对象?

TL;医生:
问题本质上是“我如何在特定实例上调用一个特权低于正常权限的方法?”。这里有三个要求:

  • 代码将根据每个实例进行授权。默认情况下,实例具有特权
  • 实例可能被选择性地列入黑名单,即,在其接收的方法调用期间,它可能被授予比通常更低的特权
  • 黑名单必须传播到代表接收者执行的代码,特别是它与之交互的同类型的任何对象,包括其本身;否则,如果,比方说,接受者依次呼叫

    AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
        this.doSomethingElse();
        return null;
    });
    
    对不受信任的方法的第一次调用有望成功,而第二次调用将失败。
    1精心编制的类的实例(例如,拥有自己的域,由某个受信任的组件分配)可能会自己行使自己的特权(在这种情况下,这并不成立,因为您似乎无法控制
    实例
    的类的实现)。然而,这仍然不能满足第二和第三个要求。
    2回想一下,在默认的
    SecurityManager
    下,当线程的
    AccessControlContext
    权限映射到所有
    ProtectionDomain
    时,就会授予
    权限。
    3如果您认为类是可信的,那么您只需在策略级别授予权限,或者根本不授予任何权限,而不必担心每个安全上下文的每个实例的权限等等。
    4这是一个艰难的决定:如果白名单不会影响同一类型的后续被调用方,那么实例将无法在自身上调用任何需要特权的方法。另一方面,现在,与原始白名单方法接收者交互的任何其他相同类型的实例也都具有特权!因此,您必须确保接收方不会调用任何其自身类型的“不受信任”实例。出于同样的原因,允许接收者生成任何线程也是一个坏主意。
    5与默认应用程序
    ClassLoader
    所采用的策略相反,默认应用程序
    ClassLoader
    将驻留在同一类路径项下的所有类分组到一个
    ProtectionDomain

    6造成不便的原因是,
    ProtectionDomain
    ,我们的自定义应用程序
    ClassLoader
    的类由其父类映射到该域,它有一个
    CodeSource
    ,这意味着所有
    CodeSource
    都引用了加载程序类路径项下的文件。到现在为止,一直都还不错。现在,当要求加载一个类时,我们的加载程序通过测试.class文件是否位于
    JAVA\u HOME
    下面,尝试区分系统/扩展类(加载它委托给其父类)和应用程序类。当然,要允许这样做,它需要对
    JAVA\u HOME
    下的文件系统子树进行读取访问。不幸的是,将相应的权限授予加载器的(众所周知的广泛)域,会隐式地将权限授予位于加载器的类路径项下的所有其他类的域,包括不受信任的类。这应该有希望解释为什么可信和不可信代码之间的类路径入门级隔离是必要的。当然,还有一些变通办法,一如往常;e、 g.要求额外签署受信任的代码,以累积任何特权;或者使用更灵活的URL方案进行代码源标识,和/或改变代码源隐含语义。
    进一步阅读:


    历史注释:最初这个答案提出了一个几乎相同的解决方案,它依赖于JAAS的
    SubjectDomainCombiner
    ,而不是定制的动态权限修改。“特殊”
    主体
    将附加到特定域,然后根据其复合的
    代码源
    -
    主体
    身份,经
    策略
    评估后,该主体将累积额外的
    权限

    AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
        this.doSomethingElse();
        return null;
    });
    
    java -cp /path/to/classpath-entry-for-trusted-code:/path/to/classpath-entry-for-untrusted-code -Djava.system.class.loader=com.example.trusted.DiscriminatingClasspathClassLoader com.example.trusted.Main