- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在编写一个 Java 系统,其中的代码在非常严格的沙箱中执行。一个查询(由一个或多个类组成)在执行期间只允许访问一个文件夹(以及文件夹中包含的子文件夹和文件)。
我通过使用 SecurityManager
和每次查询执行一个新的 ClassLoader
来强制执行沙盒。当使用 defineClass
在 ClassLoader
中定义类时,我传递了一个包含应授予的文件读取权限的 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/
上下文 我正在编写一个 Java 系统,其中的代码在非常严格的沙箱中执行。一个查询(由一个或多个类组成)在执行期间只允许访问一个文件夹(以及文件夹中包含的子文件夹和文件)。 我通过使用 Securit
我是一名优秀的程序员,十分优秀!