gpt4 book ai didi

java - AccessController 没有考虑类的 ProtectionDomain

转载 作者:塔克拉玛干 更新时间:2023-11-03 05:14:14 25 4
gpt4 key购买 nike

上下文

我正在编写一个 Java 系统,其中的代码在非常严格的沙箱中执行。一个查询(由一个或多个类组成)在执行期间只允许访问一个文件夹(以及文件夹中包含的子文件夹和文件)。

我通过使用 SecurityManager 和每次查询执行一个新的 ClassLoader 来强制执行沙盒。当使用 defineClassClassLoader 中定义类时,我传递了一个包含应授予的文件读取权限的 ProtectionDomain

由于并非调用堆栈上的所有对象都具有所需的权限,因此查询中的读取操作在 AccessController.doPrivileged(...) block 中运行。

问题

  • 当我直接从 doPrivileged(...) block 中调用 AccessController.checkPermission(...) 时,它会静默返回
  • 当我调用 System.getSecurityManager().checkPermission(...) 时,它将请求转发给 AccessController,然后 AccessController 抛出异常。
  • 当通过 SecurityManager 调用 AccessController 时,ProtectionDomain 似乎丢失了?
  • 限制文件操作(如创建 java.io.FileReader),直接调用 SecurityManager 而不是 AccessController如何让 AccessController 在通过 SecurityManager 调用时遵守调用 的类的 ProtectionDomain doRestricted(...)-block?
  • 会不会是 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;
}
});

程序生成的输出,包括部分堆栈跟踪(PATH 替换使用的长路径名):

AccessController says OK
Asked for permission: ("java.io.FilePermission" "PATH/hello" "read")
java.security.AccessControlException: access denied ("java.io.FilePermission" "PATH/hello" "read")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:366)
at java.security.AccessController.checkPermission(AccessController.java:560)
at com.aircloak.cloak.security.CloakSecurityManager.checkPermission(CloakSecurityManager.java:40)
at com.dummycorp.queries.ValidQuery$1.run(ValidQuery.java:23)
at com.dummycorp.queries.ValidQuery$1.run(ValidQuery.java:1)
at java.security.AccessController.doPrivileged(Native Method)
at com.dummycorp.queries.ValidQuery.run(ValidQuery.java:16)
at com.aircloak.cloak.security.CloakSecurityManagerTest$1.run(CloakSecurityManagerTest.java:75)
at java.lang.Thread.run(Thread.java:722)

CloakAccessController.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);
}

它的作用主要是绕过创建它的线程的安全限制。


我的java.policy的内容文件是标准 MacOSX 系统的文件。我相信它不包含任何非标准更改。

最佳答案

我觉得回答我自己的问题有点尴尬,但我找到了正确的解决方案,并认为将其添加到此处是正确的,因此将其记录在案以防有人偶然发现这个问题。

长话短说:

我的习惯SecurityManager没有正确的权限。因为它位于调用 doPrivileged(...) block 和 AccessController 之间的调用堆栈上, 特权的交集是根本没有特权。

长版

Java 安全模型的工作原理如下。当AccessController验证一个类是否被允许调用一个方法,它从调用栈的顶部到底部查看权限。如果调用堆栈中的每个条目都具有权限,则允许该操作。

这是一个任意的例子,一切正常:

+-----------+-------------------+-----------------------+
| Callstack | Class permissions | Permissions in effect |
+-----------+-------------------+-----------------------+
| Some | {Read,Write} | {Read} |
| Other | {Read} | {Read} |
+-----------+-------------------+-----------------------+

现在,就我的问题而言,调用堆栈中的较低层根本没有权限。因此,我们最终得到这样的图片,其中顶部的 query 实际上没有权限。

+-----------+-------------------+-----------------------+
| Callstack | Class permissions | Permissions in effect |
+-----------+-------------------+-----------------------+
| Query | {Read} | {} |
| Other | {} | {} |
+-----------+-------------------+-----------------------+

您可以使用 doPrivileged(...) block 来解决这个问题。这允许通过调用堆栈的权限搜索在调用特权操作的条目处结束:

+-----------+-------------------+-----------------------+
| Callstack | Class permissions | Permissions in effect |
+-----------+-------------------+-----------------------+
| Query | {Read} | {Read} |
| Other | {} | {} |
+-----------+-------------------+-----------------------+

这就是为什么当我从查询中调用 AccessController.checkPermission(...) 时一切正常的原因。毕竟它确实拥有正确的权限。 (不)幸运的是 java API(为了向后兼容)总是调用 SecurityManager .在我的例子中 SecurityManager根本没有特权。因为它实际上位于进行特权调用的查询和 AccessController 之间的调用堆栈上。 ,最终得到的权限为无:

+-----------------+-------------------+-----------------------+
| Callstack | Class permissions | Permissions in effect |
+-----------------+-------------------+-----------------------+
| SecurityManager | {} | {} |
| Query | {Read} | {Read} |
| Other | {} | {} |
+-----------------+-------------------+-----------------------+

解决方案

解决方案是给出 SecurityManager一组基本权限。结果,授予 Query 的权限确实是需要的权限:

+-----------------+---------------------+-----------------------+
| Callstack | Class permissions | Permissions in effect |
+-----------------+---------------------+-----------------------+
| SecurityManager | {Read,Write,Delete} | {Read} |
| Query | {Read} | {Read} |
| Other | {} | {} |
+-----------------+---------------------+-----------------------+

呸!那真是一口啊!希望这对外面的人有用:)

关于java - AccessController 没有考虑类的 ProtectionDomain,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13819380/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com