java的能够成为众多企业中应用广泛的语言,除了完善,强大的功能之外,重要的还有它的安全性.
java设计了从程序编写,编译,类加载过程,执行的每一步都进行安全检查.
这里简要说一下java的安全管理器和访问权限
"安全管理器是负责控制某个操作是否允许执行的类."
安全管理器负责检查的操作包括一下几个:
整个java类库中还有许多其他类似的检查.
需要注意的是,在运行java应用程序是,默认的设置是不安装安全管理器的,这样所有的操作都是允许的.另一方面,applet浏览器会执行一个功能受限的安全策略.
它的安全策略建安里了代码来源和访问权限集之间的映射关系.
以文件访问权限为例
策略类需要读取响应的安全策略文件,这些文件包含了将代码来源映射为权限的指令.
在我们的jdk中默认有两个地方可以安装安全侧路文件:
java平台主目录的java.policy文件
用户主目录的.java.policy文件(注意文件名前面的圆点)
注意:可以在java.security配置文件中修改这些文件的位置,默认位置设定为
另外一种方式是为每一个应用程序配置显示的策略文件.
(策略文件格式参考官方文档 )
启用策略文件有两种方法,一种是在应用程序的main方法内部设置系统属性:
1.
System.setProperty("java.security.policy", "app.policy");
2. 虚拟机命令行启动参数
java -Djava.security.policy=app.policy App
对于applet
applietviewer -J-Djava.security.policy=app.policy applet.html
在这些例子中,app.policy文件被添加到了其他有效的策略中.如果再命令行中添加了第二个等号,比如:
java -Djava.security.policy==app.policy App
那么应用程序就只是用指定的策略文件,而标准的策略文件将被忽略.
前面说,默认java是不安装安全管理器的.因此,在安装安全管理器之前,看不到策略文件的作用.
所以启用要启用安全管理器,一可以在main方法中添加:
System.setSecurityManager(new SecurityManager());
或者在启动虚拟机的时候添加命令行选项-Djava.security.manager
java -Djava.security.manager -Djava.security.policy=app.policy App
java.io.FilePermission 有read, write, execute 和delete四个操作
另外一个注意的地方是:
代码总是可以读取自身所在目录(或该目录的子目录)中的文件,不需要对其进行显式授权。(since JDK API 1.2)
就是说默认情况下代码总是对自身目录的文件有可读权限,但是其他write, execute 和delete权限是没有的.
这里我和搭档的测试方法是测试应用程序目录的上一个目录中的一个目录的权限.
策略文件和应用程序文件在同一目录
PermissionTest.policy
grant { permission java.util.PropertyPermission "user.dir", "read"; permission java.io.FilePermission "../test", "write"; };
需要说明的是,user.dir 这个property的读权限因为需要在应用程序中获得上级目录需要使用的java.io.File的方法,但是在执行过程中出现报错,user.dir不可读.所以应该是File的方法使用到了user.dir这个property,所以在这里也把这个权限加上.
响应的java.util.PropertyPermission权限可参考java目录中的java.policy文件响应内容,注意其中并没有user.dir属性目标.
同时,我们对测试程序本身目录中的文件进行了测试.
测试程序
PermissionTest.java
import java.io.FilePermission; import java.io.File; public class PermissionTest { public static void main(String[] args) { SecurityManager manager = System.getSecurityManager(); File f = new File(""); System.out.println(System.getProperty("user.dir")); System.out.println(f.getAbsoluteFile().getParent()); try{ manager.checkRead("../test"); System.out.println("读权限可用!"); } catch (SecurityException e) { System.out.println("读权限不可用!"); System.out.println(e.getMessage()); } try{ manager.checkWrite("../test"); System.out.println("写权限可用!"); } catch (SecurityException e) { System.out.println("写权限不可用!"); System.out.println(e.getMessage()); } try{ manager.checkDelete("../test"); System.out.println("删除权限可用!"); } catch (SecurityException e) { System.out.println("删除权限不可用!"); System.out.println(e.getMessage()); } try{ manager.checkExec(f.getAbsoluteFile().getParent() + File.separator + "test"); System.out.println("执行权限可用!"); } catch (SecurityException e) { System.out.println("执行权限不可用!"); System.out.println(e.getMessage()); } System.out.println("=======检查应用程序本身目录文件权限======="); try{ manager.checkRead("TEM"); System.out.println("TEM 读权限可用!"); } catch (SecurityException e) { System.out.println("TEM 读权限不可用!"); System.out.println(e.getMessage()); } try{ manager.checkWrite("TEM"); System.out.println("TEM 写权限可用!"); } catch (SecurityException e) { System.out.println("TEM 写权限不可用!"); System.out.println(e.getMessage()); } try{ manager.checkDelete("TEM"); System.out.println("TEM 删除权限可用!"); } catch (SecurityException e) { System.out.println("TEM 删除权限不可用!"); System.out.println(e.getMessage()); } try{ manager.checkExec(System.getProperty("user.dir") + File.separator + "TEM"); System.out.println("TEM 执行权限可用!"); } catch (SecurityException e) { System.out.println("TEM 执行权限不可用!"); System.out.println(e.getMessage()); } System.out.println("Fine."); } }
还需要说明的是检查执行权限的checkExec方法,参见JDK API
所以,checkExec需要使用绝对路径文件来调用.
当然可以通过checkPermission(Permission p)来检查,这样就不涉及到绝对路径的问题.
命令行执行测试:
java -Djava.security.manager -Djava.security.policy==PermissionTest.policy PermissionTest
修改policy文件及测试程序,可以看到不同权限的变化.
--参考资料《JAVA核心技术(Core Java)》原书第8版