Java 为什么我可以使用AccessController.doPrivileged脱离受限的AccessControlContext?
我正在研究如何在没有权限的情况下运行外部代码(来自不同的JAR),这样它就不会损害我自己的系统。我让它几乎可以工作,但是我发现一个奇怪的情况,调用Java 为什么我可以使用AccessController.doPrivileged脱离受限的AccessControlContext?,java,security,access-control,Java,Security,Access Control,我正在研究如何在没有权限的情况下运行外部代码(来自不同的JAR),这样它就不会损害我自己的系统。我让它几乎可以工作,但是我发现一个奇怪的情况,调用System.exit(0)仍然会杀死整个系统 其想法是在多线程环境中加载不同的JAR,因此在服务器上的许多其他安全风险中,System.exit(0)成功大概是最糟糕的 我有以下代码(在SSCEE中): 我的想法是,我自己的代码仍然具有完全权限,但沙盒代码限制了(在本例中为:无)权限 但是,在给定的示例中,它只是存在,请注意,main方法的以下变体确
System.exit(0)
仍然会杀死整个系统
其想法是在多线程环境中加载不同的JAR,因此在服务器上的许多其他安全风险中,System.exit(0)
成功大概是最糟糕的
我有以下代码(在SSCEE中):
我的想法是,我自己的代码仍然具有完全权限,但沙盒代码限制了(在本例中为:无)权限
但是,在给定的示例中,它只是存在,请注意,main方法的以下变体确实有效:
及
我在这里做错了什么,为什么可以执行一个提升权限的AccessController.doPrivileged
调用,而这些权限以前是受限制的?我希望以下情况之一是正确的:
AccessController.doPrivileged
可能会有一个特定的权限AccessController.doPrivileged
块中,权限将是“父级”AccessControlContext
和给定权限的交集这两个选项都会导致给定的代码正确地抛出一个
AccessControlException
,但它不会发生,为什么会出现这种情况?您没有任何沙盒代码。您拥有完全权限的代码正在使用它们。没有相关权限的代码将无法退出。解决方案应该是使用不受信任的ProtectionDomain
加载不受信任的代码
拥有提升权限的权限是毫无意义的。这相当于拥有所有权限
在OpenJDK内部,有一个
doPrivileged
的变体,它允许权限的交叉,但是当存在多个不信任源时,它可以降低权限。我已经多年没有研究过这个了,但是,IIRC,有一个可以“安装”的安全控制器在JVM中验证doPrivileged
调用等。如果您没有安装自己的控制器,则此控制器的默认操作是在请求通过时挥手微笑。@Hotlick通常通过SecurityManager
进行权限检查,然后将其转发到AccessController
类AccessController.doPrivileged
无法将权限提升到调用类的权限之上。(处理DomainCombiner
和Subject
有单独的规则)
public class RestrictAccessControlContext {
private static final PermissionCollection ALLOWED_PERMISSIONS = new Permissions();
static {
//add permissions
}
private static final AccessControlContext RESTRICTED_ACCESS_CONTROL_CONTEXT =
new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, ALLOWED_PERMISSIONS)});
private static void executeSandboxed(final Runnable runnable) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<?> future = executorService.submit(() -> {
AccessController.doPrivileged((PrivilegedAction<Void>)() -> {
runnable.run();
return null;
}, RESTRICTED_ACCESS_CONTROL_CONTEXT);
});
try {
future.get();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
} catch (ExecutionException ex) {
throw new RuntimeException(ex.getCause());
} finally {
executorService.shutdown();
}
}
public static void main(String[] args) {
executeSandboxed(() -> {
AccessController.doPrivileged((PrivilegedAction<Void>)() -> {
System.exit(0);
return null;
});
});
}
}
grant {
permission java.security.AllPermission;
};
public static void main(String[] args) {
executeSandboxed(() -> System.exit(0));
}
public static void main(String[] args) {
executeSandboxed(() -> new Thread(() -> System.exit(0)).start());
}