所以我有一些代码,它创建了一个类的实例。
Class<?> c = Class.forName("MyClass");
Constructor<?> cons = c.getConstructor();
cons.setAccessible(true);
Object instance = cons.newInstance();
现在我想为该实例设置一些限制。我打电话的时候:
instance.doSomething();
我想为(位实例的)代码设置限制。因此,从isntance调用的方法不能做一些可疑的事情(系统调用,文件操作......)。
我曾尝试设置安全管理器,但是这会限制所有代码(我仍然想要读取/写入其余代码的文件)。 是否可以仅限制某些对象?
答案 0 :(得分:2)
TL; DR:Code
<小时/> 问题基本上是&#34;如何在特定实例上调用方法,权限低于正常?&#34; 。这里有三个要求:
黑名单必须传播到代表接收者执行的代码,特别是与其交互的相同类型的任何对象,包括其自身;否则,如果接收者轮流打电话
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
this.doSomethingElse();
return null;
});
doSomethingElse()
会逃离沙箱。
这三个都有问题:
AccessController.doPrivileged(...)
声明其自己的(默认的,基于类的)特权时才可以实现,这可能是设计的随时选择。 还有替代方案吗?
那么,你愿意走多远?修改AccessController
/ AccessControlContext
内幕?或者更糟糕的是,VM的内部?或者也许提供自己的SecurityManager
重新实现上述组件&#39;功能从零开始,以满足您的要求的方式?如果对所有人的回答是&#34; no&#34;,那么我担心你的选择是有限的。
顺便说一下,理想情况下,当你被问到时,你应该能够做出二元选择吗?这个特定的代码,即类,能否或者不能被赋予特定的特权? &#34; ,因为这将极大地简化 3 事物。不幸的是你不能;而且,更糟糕的是,你可能也不可能修改班级的实施,以便所有的实例都可以考虑 - 关于特定的一组特权 - 值得信赖,也不希望简单地标记这个类,因此它的所有实例都是不可信的(我相信你应该这样做!)并与它一起生活。
继续讨论建议的解决方法。为了克服前面列出的缺点,原始问题将被重新描述如下:&#34;如何使用提升特权来调用方法接收器&#39; s ProtectionDomain
?&#34; 我将回答这个衍生问题,建议与原始问题相反:
ProtectionDomain
授权,通常情况下如此。默认情况下,代码是沙箱。修订后的要求将通过自定义ClassLoader
和DomainCombiner
来满足。第一个目的是为每个类 5 分配一个不同的ProtectionDomain
;另一个是暂时替换当前AccessControlContext
内各个类的域名,以便按需白名单&#34;目的。另外扩展SecurityManager
以防止非特权代码 4 创建线程。
运行示例
根据示例策略配置文件的建议编译和部署代码,即应该有两个 6 不相关的类路径条目(例如,兄弟目录在文件系统级别) - 一个用于com.example.trusted
包的类,另一个用于com.example.untrusted.Nasty
。
确保您已将策略配置替换为示例配置,并已根据需要修改其中的路径。
最后运行(当然,在适当修改了类路径条目之后):
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
第一次调用不受信任的方法应该会成功,第二次调用失败。
<小时/> 1 特制类的实例(例如,由某个可信组件分配的,具有自己的域)的实例可能会行使自己的权限自己< / em>(在这种情况下不成立,因为你无法控制instance
类的实现,它出现了)。然而,这仍然不能满足第二和第三个要求。 SecurityManager
下,当所有Permission
s-通常是类而不是实例时,都会授予ProtectionDomain
映射了该权限的AccessControlContext
imply线程。 ClassLoader
使用的策略相反,默认应用程序ProtectionDomain
用于将位于同一类路径条目下的所有类分组到一个ProtectionDomain
内。< /子> ClassLoader
的类被其父级映射到的CodeSource
具有CodeSource
{1}}暗示所有JAVA_HOME
引用加载程序的类路径条目下的文件。到现在为止还挺好。现在,当被要求加载一个类时,我们的加载器会尝试通过测试.class文件是否位于JAVA_HOME
之下来分辨系统/扩展类(它委托给它的父级)和应用程序类。当然,要允许这样做,它需要对SubjectDomainCombiner
下的文件系统子树进行读取访问。不幸的是,向我们的加载器(众所周知的广泛)域授予相应的权限,隐式地将权限授予驻留在加载器的类路径条目下的所有其他类的域,包括不受信任的域。这应该有希望解释为什么必须在可信代码和不可信代码之间进行类路径入口级隔离。当然,一如既往地有解决方法;例如强制要求对可信代码进行额外签名以获得任何特权;或者使用更灵活的URL方案进行代码源识别,和/或改变代码源隐含语义。
进一步阅读:
<小时/> 历史记录:最初这个答案提出了一个几乎相同的解决方案,
Principal
,而不是自定义的,用于动态权限修改。 A&#34;特别&#34; Permission
会附加到特定域名,然后Policy
会根据其CodeSource
- Principal
个身份对{{1}}进行评估,从而产生额外的{{1}}。