如何禁用Java安全管理器?

18

有没有完全禁用Java安全管理器的方法?

我正在尝试使用db4o源代码。它使用反射来持久化对象,但似乎安全管理器不允许反射读取和写入私有或受保护字段。

我的代码:

public static void main(String[] args) throws IOException {
    System.out.println("start");
    new File( DB_FILE_NAME ).delete();
    ObjectContainer container = Db4o.openFile( DB_FILE_NAME );
    String ob = new String( "test" );
    container.store( ob );
    ObjectSet result = container.queryByExample( String.class );
    System.out.println( "retrieved (" + result.size() + "):" );
    while( result.hasNext() ) {
        System.out.println( result.next() );
    }
    container.close();
    System.out.println("finish");
}

输出:

开始
[db4o 7.4.68.12069 2009-04-18 00:21:30]
 AccessibleObject#setAccessible() 不可用。私有字段无法存储。
检索到的 (0):
完成


此线程建议修改 java.policy 文件以允许反射,但对我似乎没有用。

我使用以下参数启动 JVM:
-Djava.security.manager -Djava.security.policy==/home/pablo/.java.policy
所以指定的策略文件将是唯一使用的策略文件。

文件内容如下:

grant {
    permission java.security.AllPermission;
    permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};

我花了过去 3 个小时试图解决这个问题,但没有任何想法如何使其工作。 感激任何帮助。


你是否尝试从自己的代码中调用setAccessible或其他特权操作? - Tom Hawtin - tackline
完整的命令行也可能很有用。 - Tom Hawtin - tackline
1
你的虚拟机参数是否正确?你似乎有 -Djava.security.policy==? - Brian Agnew
5
@Brian: 双等号表示指定的文件是唯一使用的策略文件。单等号表示指定的文件将与标准策略文件一起使用。至少这是我所读到的。 - Pawel Piatkowski
@Tom:我可以在我的代码中调用setAccessible,这很奇怪,因为我的代码是我添加到db4o源代码中的一个类。然而,同样的db4o似乎无法访问setAccessible。也许这是db4o的一个bug? - Pawel Piatkowski
3个回答

7
您可以尝试将以下内容添加到程序的main()函数中:
System.setSecurityManager(null);

当我遇到安全管理器问题时,这个方法对于一个“可信任”的WebStart应用程序对我很有帮助。我不确定它是否适用于您的db4o情况,但值得一试。

编辑:我并不是在暗示这是解决安全管理器问题的通用方法。我只是提出它作为帮助调试原帖问题的一种方式。显然,如果您想从安全管理器中受益,那么就不应该禁用它。


1
一般不建议这样做,因为恶意代码可以利用它来破坏安全性并获取本地用户权限。 - Tom Hawtin - tackline
8
原帖作者确实想要“完全禁用”安全管理器! :-) - Brian Agnew
谢谢,我在“受信任”的WebStart应用程序中遇到了异常,调用System.setSecurityManager(null);对我有帮助。 - siddagrl
2
安全管理器可以防止设置安全管理器,这对攻击者来说是不好的,但它允许创建一个“超级”安全管理器,在程序流的其余部分中保持永久。 - gparyani
1
@gparyani:没错,谢谢。更进一步地说,程序必须具有java.lang.RuntimePermissionsetSecurityManager权限才能设置安全管理器。 - Sadeq Dousti

5
你在java.security.policy命令行选项中真的有两个'='号吗?那样是行不通的。确保你设置属性为:
-Djava.security.policy=/home/pablo/.java.policy

为了真正禁用 SecurityManager,只需完全省略 java.security.manager 系统属性即可。
更新: 当我阅读策略文件文档以了解有关“==”语法的更多信息时,我注意到,除非策略文件在当前工作目录中,否则它需要被指定为 URL(包括方案)。您尝试使用 "file:" 方案前缀策略路径了吗?
我也感到困惑,因为(假设您正在以用户 "pablo" 运行),似乎该策略应默认从您的主目录加载,因此您根本不需要指定它。另一方面,如果您没有作为用户 "pablo" 运行,则可能无法读取该文件。

5
那不行。同样,未向JVM传递任何参数也是不行的。顺便说一下,'==' 表示指定的文件将是唯一使用的文件。单个 '=' 表示该文件将与标准策略文件一起使用。至少这是我所读到的。 - Pawel Piatkowski

4
我发现了一个关于如何让私有字段和方法在你的代码中可访问的示例(make private fields and methods accessible)。基本上,它可以归结为使用Field.setAccessible(true)Method.setAccessible(true)
字段示例:
Field privateStringField = PrivateObject.class.
            getDeclaredField("privateString");

privateStringField.setAccessible(true);

方法示例:

Method privateStringMethod = PrivateObject.class.
        getDeclaredMethod("getPrivateString", null);

privateStringMethod.setAccessible(true);

你还可以考虑在Java代码中使用Groovy,因为它(目前)规避了Java代码的许多访问级别限制。尽管如此,这篇留言板帖子似乎表明这个“特性” 可能会在未来版本的Groovy中改变

7
如果禁用安全管理器,您就可以调用setAccessible(true)来获得权限。如果不禁用安全管理器,您就不可能做到这一点。 - extraneon
@Kevin:我可以在自己的代码中调用setAccessible来访问私有字段。而我的“自己的代码”是指我添加到db4o源代码中的类。 - Pawel Piatkowski
只要您不在应用程序或其他具有违反安全管理器的环境中运行它,就可以在代码中调用它,正如@extraneon所建议的那样。这篇Artima文章对Java安全管理器有很好的解释:http://www.artima.com/underthehood/securitymanager.html - Kevin Williams

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