Seb*_*ide 6 java security permissions sandbox securitymanager
我正在编写一个Java系统,其中代码在非常严格的沙箱中执行.一个查询(由一个或多个类组成)应该只允许在执行期间访问一个文件夹(以及文件夹中包含的子文件夹和文件).
我通过使用a SecurityManager和新的ClassLoader每个查询执行来强制执行沙盒.当在定义类的ClassLoader使用defineClass,我沿着传递ProtectionDomain包含应授予该文件的读取权限.
由于并非调用堆栈上的所有对象都具有所需的权限,因此查询中的读取操作在AccessController.doPrivileged(...)-block 中运行.
AccessController.checkPermission(...)从doPrivileged(...)块内直接调用时,它会以静默方式返回System.getSecurityManager().checkPermission(...),将请求转发给AccessController,然后AccessController抛出异常.ProtectionDomain似乎打电话时迷路AccessController通过SecurityManager?java.io.FileReader),直接调用SecurityManager而不是AccessController.我如何获得的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;
}
});
Run Code Online (Sandbox Code Playgroud)
程序生成的输出,包括堆栈跟踪的部分(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)
Run Code Online (Sandbox Code Playgroud)
该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);
}
Run Code Online (Sandbox Code Playgroud)
它的作用主要是绕过了创建它的线程的安全限制.
我的java.policy文件的内容是标准MacOSX系统的内容.我相信它不包含任何非标准的更改.
我觉得有点尴尬地回答我自己的问题,但是我找到了正确的解决方案,并且认为只在这里添加它是正确的,所以如果有人偶然发现这个问题,它将被记录下来.
我的自定义SecurityManager没有正确的权限.由于它位于调用doPrivileged(...)-block和AccessController的类之间的callstack上,因此权限的交集完全没有权限.
Java安全模型的工作原理如下.当AccessController验证是否允许类调用某个方法时,它会查看从callstack顶部到底部的权限.如果callstack中的每个条目都具有该权限,则允许该操作.
这是一个任意的例子,一切都很好:
+-----------+-------------------+-----------------------+
| Callstack | Class permissions | Permissions in effect |
+-----------+-------------------+-----------------------+
| Some | {Read,Write} | {Read} |
| Other | {Read} | {Read} |
+-----------+-------------------+-----------------------+
Run Code Online (Sandbox Code Playgroud)
现在,就我的问题而言,callstack中的较低层根本没有权限.因此我们最终得到了这样的图片,其中query顶部实际上没有权限.
+-----------+-------------------+-----------------------+
| Callstack | Class permissions | Permissions in effect |
+-----------+-------------------+-----------------------+
| Query | {Read} | {} |
| Other | {} | {} |
+-----------+-------------------+-----------------------+
Run Code Online (Sandbox Code Playgroud)
您可以使用doPrivileged(...)-block 解决此问题.这允许通过callstack的权限搜索在调用特权操作的条目处结束:
+-----------+-------------------+-----------------------+
| Callstack | Class permissions | Permissions in effect |
+-----------+-------------------+-----------------------+
| Query | {Read} | {Read} |
| Other | {} | {} |
+-----------+-------------------+-----------------------+
Run Code Online (Sandbox Code Playgroud)
这就是我AccessController.checkPermission(...)在查询中调用from 时一切正常的原因.毕竟它确实拥有正确的权限.(Un)幸运的是java API(为了向后兼容),总是调用SecurityManager.在我的情况下,SecurityManager根本没有任何权限.因为它实际上是在进行特权调用的查询和AccessController之间的callstack上,所以net结果权限是none:
+-----------------+-------------------+-----------------------+
| Callstack | Class permissions | Permissions in effect |
+-----------------+-------------------+-----------------------+
| SecurityManager | {} | {} |
| Query | {Read} | {Read} |
| Other | {} | {} |
+-----------------+-------------------+-----------------------+
Run Code Online (Sandbox Code Playgroud)
解决方案是为SecurityManager提供一组基本权限.因此,授予Query的权限确实是所需的权限:
+-----------------+---------------------+-----------------------+
| Callstack | Class permissions | Permissions in effect |
+-----------------+---------------------+-----------------------+
| SecurityManager | {Read,Write,Delete} | {Read} |
| Query | {Read} | {Read} |
| Other | {} | {} |
+-----------------+---------------------+-----------------------+
Run Code Online (Sandbox Code Playgroud)
唷!那真是一口气!希望这对那里的人有用:)
| 归档时间: |
|
| 查看次数: |
1457 次 |
| 最近记录: |