启用Java SecurityManager并授予AllPermission权限

15

我正在努力熟悉SecurityManager,但是即使是这个简单的场景也失败了。 当我从我的IDE内部或命令行运行以下内容时,我会得到以下异常

access denied ("java.util.PropertyPermission" "java.home" "read")

我认为这段代码已经允许了一切:

Policy.setPolicy(new Policy() {

    @Override
    public PermissionCollection getPermissions(CodeSource codesource) {
        Permissions perm = new Permissions();
        perm.add(new AllPermission());
        return perm;
    }
});
System.setSecurityManager(new SecurityManager());
System.out.println(System.getProperty("java.home"));
这与JVM导出的策略有关吗? 我该如何干净地setPolicy()

对于以下代码,同样会发生误解:

System.setSecurityManager(new SecurityManager());
final Permissions allPermission = new Permissions();
allPermission.add(new AllPermission());
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
    System.out.println(System.getProperty("java.home"));
    return null;
}, new AccessControlContext(new ProtectionDomain[]{new ProtectionDomain(null, allPermission)}));

更新:第二种情况是可以理解的,因为提供的权限只是进一步的限制:(javadoc)该操作是在调用者保护域所拥有的权限和由指定的 AccessControlContext 表示的域所拥有的权限的交集下执行的。


我正在尝试提高我的Java应用程序的安全性,为此我需要了解其机制。仅启用SecurityManager是不可能的,因为我需要一些例外情况。我必须更深入地了解所有这些如何协同工作,因为这不是标准用例。 - Karussell
我无法重现这个问题(已在JDK 8和11上尝试)。 我怀疑默认策略实现不是原因。 在安全管理器和您的自定义策略之间插入了某些非标准内容,有效地阻止或覆盖对后者的查询; 例如,一个自定义类加载器为您的类分配了一个[静态](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/security/ProtectionDomain.html#%3Cinit%3E(java.security.CodeSource,java.security.PermissionCollection)),非特权保护域。 - Uux
@Uux 非常感谢您抽出时间。那么在您的情况下,您可以访问java.home属性吗?如果是的话,您能否分享一下您的策略文件? - Karussell
1
@Karussell 是的,您的代码片段运行得非常好(在一个普通的 main 方法内运行,通过普通的 java -cp <classpath> <main-class> 启动)。我没有修改我的 .policy 文件,因为最终它并不重要--一旦 Policy.setPolicy 返回,就会咨询 的策略实现,而不是以前的、默认的、文件支持的那个。你可以尝试使用 -Djava.security.debug="access,failure" 运行并将其输出附加到你的问题上。 - Uux
我现在更清楚自己想要实现什么了:我想要一种编程方式来设置策略,其中如果我不设置权限,则 System.getProperty 调用会失败,如果我授予 PropertyPermission 或 AllPermission,则调用将成功。确实,第二部分现在可以工作(不知道为什么),但是第一部分没有任何权限就可以通过。当我执行 Policy.getPolicy 时,恰好相反的情况发生了(两个部分都失败了)。 - Karussell
相关但不完全重复的问题:https://stackoverflow.com/questions/31458821/policy-setpolicy-doesnt-seem-to-work-properly - Caesar
3个回答

15

我能够通过在Policy.setPolicy()之前加上一个额外的Policy.getPolicy()来重现您的情况,它会影响行为的原因是,在进行获取策略调用时,会触发默认策略创建,并设置来自java.policy的权限,但如果没有setSecurityManager(),它们不会被激活,这就是当您进行自定义AllPermission策略设置时,仍然会出现"java.util.PropertyPermission" "java.home" "read"问题的原因,因为许多这样的默认策略没有被覆盖。非常混乱的结构。

Policy.getPolicy();
Policy.setPolicy(policyWithAllPermission);
System.setSecurityManager(new SecurityManager());
System.out.println(System.getProperty("java.home"));
// results in 'access denied ("java.util.PropertyPermission" "java.home" "read")'

但是,如果您使用以下自定义策略;

Policy allPermissionPolicy = new Policy() {

    @Override
    public boolean implies(ProtectionDomain domain, Permission permission) {
        return true;
    }
};

它覆盖了所有权限定义,使得所有的操作都可以通过,这可能是解决混淆的一种方法。


2
原来你从一开始就直觉地走在了正确的轨道上(如果你注意到评论中提到在调用 setPolicy 之前先调用 getPolicy,那么就额外加分了)!至于这个故事的“为什么”部分,请参阅 java.security.Policy#initPolicy 的源代码。 - Uux

1
在什么上下文中运行您上面的代码?是在简单JVM中从命令行运行还是在某个JavaEE容器上运行的Web应用程序中?使用哪个操作系统?使用哪个JVM(Oracle、OpenJDK、IBM J9等)以及哪个版本?如果您是从命令行运行,请查看位于JVM安装路径中的java.policy文件。它的内容可能会限制您的授权,从而防止您访问此特定的系统变量?

我已经更新了我的问题。因此,策略文件会覆盖Policy.setPolicy吗?如果真是这样,那么这种方法的Javadocs就更具误导性了。 - Karussell

0

最终,如果你需要一个允许一切的SecurityManager,只需使用以下代码:

System.setSecurityManager(new SecurityManager() {
    @Override
    public void checkPermission(Permission perm) {
    }

    @Override
    public void checkPermission(Permission perm, Object context) {
    }
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接