语境
我正在编写一个 Java 系统,其中代码在非常严格的沙箱中执行。查询(由一个或多个类组成)在执行期间只允许访问一个文件夹(以及文件夹中包含的子文件夹和文件)。
我通过使用一个SecurityManager
, 和一个新的ClassLoader
每个查询执行来强制沙盒。在ClassLoader
using中定义类时defineClass
,我传递了一个ProtectionDomain
包含应该授予的文件读取权限的文件。
由于并非调用堆栈上的所有对象都具有所需的权限,因此查询中的读取操作在AccessController.doPrivileged(...)
-block 内运行。
问题
- 当我
AccessController.checkPermission(...)
直接从doPrivileged(...)
块内调用时,它会静默返回 - 当我调用
System.getSecurityManager().checkPermission(...)
将请求转发到 时AccessController
,会AccessController
引发异常。 - 通过?
ProtectionDomain
呼叫时似乎迷路AccessController
了SecurityManager
? - 受限制的文件操作(如创建
java.io.FileReader
),直接调用SecurityManager
而不是AccessController
. 当通过 调用时,如何让 尊重调用-block 的类的 ?AccessController
SecurityManager
ProtectionDomain
doRestricted(...)
- 可能是它
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 系统的内容。我相信它不包含任何非标准的变化。