Java AccessController不接受类';考虑到ProtectionDomain 上下文
我正在编写一个Java系统,其中代码在非常严格的沙盒中执行。查询(由一个或多个类组成)在执行期间只能访问一个文件夹(以及文件夹中包含的子文件夹和文件) 我通过在每次查询执行时使用Java AccessController不接受类';考虑到ProtectionDomain 上下文,java,security,permissions,securitymanager,sandbox,Java,Security,Permissions,Securitymanager,Sandbox,我正在编写一个Java系统,其中代码在非常严格的沙盒中执行。查询(由一个或多个类组成)在执行期间只能访问一个文件夹(以及文件夹中包含的子文件夹和文件) 我通过在每次查询执行时使用SecurityManager和新的ClassLoader来实施沙箱。使用defineClass在ClassLoader中定义类时,我会传递一个ProtectionDomain,其中包含应授予的文件读取权限 由于并非调用堆栈上的所有对象都具有所需的权限,因此查询中的读取操作在AccessController.doPriv
SecurityManager
和新的ClassLoader
来实施沙箱。使用defineClass
在ClassLoader
中定义类时,我会传递一个ProtectionDomain
,其中包含应授予的文件读取权限
由于并非调用堆栈上的所有对象都具有所需的权限,因此查询中的读取操作在AccessController.doPrivileged(…)
-块中运行
问题
- 当我直接从
块中调用doPrivileged(…)
时,它会以静默方式返回AccessController.checkPermission(…)
- 当我调用将请求转发给
的AccessController
时,System.getSecurityManager().checkPermission(…)
抛出异常AccessController
- 通过
调用SecurityManager
时,AccessController
似乎丢失了ProtectionDomain
- 受限文件操作(如创建
),直接调用java.io.FileReader
,而不是SecurityManager
当通过AccessController
调用SecurityManager
时,如何让它尊重调用AccessController
-块的类的doRestricted(…)
ProtectionDomain
- 是否
本身没有所需的权限?因此,通过被夹在特权代码和SecurityManager
之间的调用堆栈中,会生成一个无特权联合李>AccessController
AccessController.doPrivileged(new PrivilegedAction<QueryResult>() {
public QueryResult run() {
String location = folderName + "/hello";
FilePermission p = new FilePermission(location, "read");
try {
AccessController.checkPermission(p); // Doesn't raise an exception
System.out.println("AccessController says OK");
System.getSecurityManager().checkPermission(p); // Raises AccessControlException
System.out.println("SecurityManager says OK");
} catch (AccessControlException e) {
System.out.println("### Not allowed to read");
}
return null;
}
});
CoverAccessController.checkPermission(…)
实现可能也很有趣。看起来是这样的:
public void checkPermission(Permission perm) {
if (Thread.currentThread().getId() == this.masterThread) {
return;
} else {
System.out.println("Asked for permission: "+perm.toString());
}
AccessController.checkPermission(perm);
}
它所做的主要是绕过创建它的线程的安全限制
我的文件的内容是标准MacOSX系统的内容。我相信它不包含任何非标准更改。我认为这里的问题在于如何为
SecurityManager
提供ProtectionDomain
如果您想自己加载类,并且能够使用SM,那么应该扩展。此类为方法提供了模板:
protected Class defineClass(String name, byte[] b, int off, int len, CodeSource cs)
在其中,您应该为您的类提供CodeSource
。然后是另一种方法:
protected PermissionCollection getPermissions(CodeSource codesource)
对于给定的类,它将返回
PermissionCollection
。这就是为动态加载的类实现动态权限的方法。回答我自己的问题时,我感到有点尴尬,但我找到了正确的解决方案,并且认为将其添加到此处才是正确的,因此,为了防止将来有人在这个问题上遇到问题,将对其进行记录
TL;博士:
我的自定义没有正确的权限。由于它位于调用doPrivileged(…)
-块的类和之间的调用堆栈上,所以特权的交集根本就不是特权
长版本
Java安全模型的工作原理如下。当验证是否允许类调用方法时,它会从调用堆栈的顶部向底部查看权限。如果callstack中的每个条目都有权限,则允许该操作
这是一个任意的例子,一切都很顺利:
+-----------+-------------------+-----------------------+
| Callstack | Class permissions | Permissions in effect |
+-----------+-------------------+-----------------------+
| Some | {Read,Write} | {Read} |
| Other | {Read} | {Read} |
+-----------+-------------------+-----------------------+
现在,在我的问题中,调用堆栈中的较低层根本没有权限。
因此,我们最终得到这样一幅图片,上面的查询
实际上没有权限
+-----------+-------------------+-----------------------+
| Callstack | Class permissions | Permissions in effect |
+-----------+-------------------+-----------------------+
| Query | {Read} | {} |
| Other | {} | {} |
+-----------+-------------------+-----------------------+
您可以通过使用doPrivileged(…)
-块绕过这个问题。这允许通过调用堆栈的权限搜索在调用特权操作的条目处结束:
+-----------+-------------------+-----------------------+
| Callstack | Class permissions | Permissions in effect |
+-----------+-------------------+-----------------------+
| Query | {Read} | {Read} |
| Other | {} | {} |
+-----------+-------------------+-----------------------+
这就是为什么当我从查询中调用AccessController.checkPermission(…)
时,一切都正常工作的原因。毕竟,它确实拥有正确的权限。(Un)幸运的是,JavaAPI(为了向后兼容)总是调用。就我而言,他们根本没有特权。由于它实际上位于进行特权调用的查询与之间的调用堆栈上,因此产生的净权限为无:
+-----------------+-------------------+-----------------------+
| Callstack | Class permissions | Permissions in effect |
+-----------------+-------------------+-----------------------+
| SecurityManager | {} | {} |
| Query | {Read} | {Read} |
| Other | {} | {} |
+-----------------+-------------------+-----------------------+
解决方案
解决方案是为用户提供一组基本权限。因此,授予查询的权限确实是所需的权限:
+-----------------+---------------------+-----------------------+
| Callstack | Class permissions | Permissions in effect |
+-----------------+---------------------+-----------------------+
| SecurityManager | {Read,Write,Delete} | {Read} |
| Query | {Read} | {Read} |
| Other | {} | {} |
+-----------------+---------------------+-----------------------+
呸!那真是太多了!希望这对其他人有用:)为了完整性,请插入此权限的策略文件条目。还可以尝试使用SecurityManager.checkPermission插入AccessController。checkPermission@fatfredyy在上面发布了我的java.policy文件。使用SecurityManager.checkPermission而不是AccessController.checkPermission非常好。我更改了它,现在我的支票也抛出了AccessControlException。通过SecurityManager时权限似乎丢失了?这完全改变了我的问题。我会相应地更新它。谢谢谢谢@fatfredyy,我现在根据您的评论更改了问题。事实证明,现在的问题完全不同了。从我所看到的情况来看,您没有修改策略文件。。。如何为代码提供许可?您的代码是从ext java lib path还是从系统java lib path加载的?出于所有目的,我将这些类作为字节数组传递给我。然后,在我的类加载器中,我调用
defineClass(名称、二进制、保护域)
。保护域也由类加载器创建,并且完全包含我想要的权限集
+-----------------+---------------------+-----------------------+
| Callstack | Class permissions | Permissions in effect |
+-----------------+---------------------+-----------------------+
| SecurityManager | {Read,Write,Delete} | {Read} |
| Query | {Read} | {Read} |
| Other | {} | {} |
+-----------------+---------------------+-----------------------+