京山游侠

专注技术 拒绝扯淡
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

使用 SecurityManager 和 Policy File 管理 Java 程序的权限

Posted on 2016-08-04 15:48  京山游侠  阅读(3372)  评论(2编辑  收藏  举报

参考资料##

该文中的内容来源于 Oracle 的官方文档。Oracle 在 Java 方面的文档是非常完善的。对 Java 8 感兴趣的朋友,可以从这个总入口 Java SE 8 Documentation 开始寻找感兴趣的内容。本博客不定期从 Oracle 官网搬砖。

前言##

Java 在 Security 方面的特性,总是被很多人当做宣传的重点,但是对我而言,这基本上是八百年都用不到一次的特性。可是没办法,为了知识体系的完整性,我也不得不硬着头皮学习这些八竿子都打不着的内容。

很多 Java 程序默认在一个安全的环境中运行,比如 Applet程序。当这些在安全环境中运行的程序需要访问我们系统中的资源时,就会受到限制。换句话说,就是当 Applet 之类的程序运行时,默认就会启动一个 SecurityManager,SecurityManager 负责检查该程序是否具有相应的权限。但是很多 Java 程序不会默认启动 SecurityManager,比如大部分在我们系统中直接运行的 Java 程序。没有启用 SecurityManager 的程序的权限不会受到限制,如果存在恶意代码的话,就会产生安全问题。如果我们非要放宽对它们的限制的话,就需要对相应的 Java 程序进行授权,授权需要用到 Policy File。

没有启用 SecurityManager 的程序可以访问系统中的任意资源##

废话少说,直接开始实战。先看两个示例程序,GetProps.javaCount.java,它们一个需要访问 Java 运行环境中的 Properties,一个需要读取磁盘上的文件。代码如下图:

编译、打包、运行,这两个程序的运行结果非常符合预期,如下图:

从上图中可以看出,我在打包的时候没有使用 jar-e 选项指定程序的入口点,只是简单的把所有的 .class 打成一个 jar 包而已。运行的时候使用 java -cp HelloWorld.jar 将该 jar 包指定为 CLASSPATH 并直接运行其中的类。其实这里的程序不打包也可以运行,但是要对程序进行签名,就必须得打包了。

启用了 SecurityManager 的程序权限会被限制##

如果启用 SecurityManager,则程序的权限会受到限制。怎么启用 SecurityManager 呢?有两个办法,一个办法是在启动程序的使用使用 java -Djava.security.manager 选项,另一个办法是在代码中使用 System.setSecurityManager(new SecurityManager());。先看下图,使用第一种办法开启 SecurityManager:

可以看到,一旦使用 java -Djava.security.manager 选项启动,程序 GetPropsCount 都产生了异常。我们也可以在代码中启用 SecurityManager,也可以手动调用 SecurityManager 的方法来验证运行的程序是否具有相应的权限。请看下图示例程序 SecurityOnByCode.java

编译、打包、运行,果然产生了异常,如下图:

使用 Policy File 为程序授权##

如果要让启用了 SecurityManager 的程序正常运行,就必须对它们进行相应的授权。在本例中,需要对 GetPropsSecurityOnByCode 示例程序授予它访问 System Properties 的权限,为 Count 示例程序授予访问目录 src/com/xkland/sample 中文件的权限。授权是使用 Policy File 来控制的。系统中有一个全局的 Policy File,它的路径是 ${java.home}/lib/security/java.policy,另外还可以为当前用户定义一个用户级别的 Policy File,只要这个文件的路径是 ${user.home}/.java.policy 就行。也可以编写其它的任意的 Policy File,只需要在启动程序的时候用 java -Djava.security.policy= 选项指定 Policy File 的路径即可。

在 JDK 提供的工具中,有一个 policytool,这是一个 GUI 程序,它可以极大地简化我们编写 Policy File 的过程,后面的实战中会用到它。首先,先来为需要访问 System Properties 的程序授权,我制定一个这样的策略:位于 ${user.home}/HelloJavaWorld 目录下的程序可以访问 System Properties,这就需要用到基于 CodeBase 的授权。在本例中,我使用 policytool 创建一个 youxia.policy 文件,并基于 CodeBase 授予相应的访问 System Properties 的 java.util.PropertyPermission,如下图:

可以使用 cat youxia.policy 命令查看生成的 Policy File 的内容。授权之后再运行 GetProps 程序和 SecurityOnByCode 程序,发现它们都能顺利运行,没有产生任何异常,如下图:

但是另外一个程序 Count 仍然受限的,因为我们没有给它授予访问文件的权限。下面来解决这个问题,我设计的策略是如果该程序是被 youxia 的证书签名的,则授予它访问 src/com/xkland/sample 目录下所有文件的权利。这就需要用到基于 SignedBy 的授权。使用该类型的授权必须先指定密钥库(keystore),而密钥库的类型、供应方和口令是可以留空的,如下图:

然后再添加相应的授权,如下图:

最后来看运行效果。先常规使用 cat youxia.policy 看看,发现 Policy File 中多了一个 Grant SignedBy "youxia" 的条目,然后对 HelloWorld.jar 使用 youxia 的证书进行签名,最后运行程序,结果一切正常。如下图:

总结##

Java 领域中一些关于安全的特性往往是商家宣传的重点,但是对于我们普通开发者而言,用到这些特性的机会很少,因此往往会比较陌生。关于证书和密钥库的内容,请看这里 JDK中的证书生成和管理工具keytool, 关于 jar 文件签名和验证的内容,请看这里 Java程序的打包、签名和验证。这一篇中涉及到的 SecurityManager 和 Policy File 本身并不难,按我这个实战的流程走一遍即可了然于胸。