首先,现在已经很少人用applet,applet本身也算是快要没落的技术了。然而,最近根据项目需要,开始研究和学习applet。有了一点收获,拿来大家分享。写的不好欢迎指正,但是诸如applet已经淘汰之类的话,请免开尊口,浪费你我的时间。
众所周知,Java具有很好的安全控制,就是有名的沙盒模型。Applet可以在沙盒里做任何事情,但不能读或修改沙盒外的任何数据。沙盒”模型的思想是在信任的环境中运行不信任的代码,这样即使用户不小心引入了不安全的applet,applet也不会对系统造成破坏。关于沙盒模型的结构再次我将不再赘述,网上都可以搜到。
首先,补充下 Java中安全策略的概念的概念(下面两段整理自网上)
Java应用程序环境的安全策略,详细说明了对于不同的代码所拥有的不同资源的许可,它由一个Policy对象来表达。为了让applet(或者运行在 SecurityManager下的一个应用程序)能够执行受保护的行为,例如读写文件,applet(或 Java应用程序)必须获得那项操作的许可,安全策略文件就是用来实现这些许可。
Policy对象可能有多个实体,虽然任何时候只能有一个起作用。当前安装的Policy对象,在程序中可以通过调用getPolicy方法得到,也可以通过调用setPolicy方法改变。Policy对象评估整个策略,返回一个适当的Permissions对象,详细说明哪些代码可以访问哪些资源。 策略文件可以储存在无格式的ASCII文件或Policy类的二进制文件或数据库中。本文仅讨论无格式的ASCII文件的形式。
关于Policy的格式,如果装了JRE或JDK,可以在\jdk安装目录\jre\lib\security\java.policy文件和\jdk安装目录\jre\lib\security\java.security\java.policy下面找到。里面主要规定了给予不同程序的不同的权限。
其次,说明一下policy的加载顺序。当调用policy文件时,系统会装载.java.policy文件到系统中。首先加载系统的policy文件,然后用户的Policy,这里的方式是叠加,取用户和系统规定的权限的最大值。如果两者的policy都不存在则加载系统默认的policy文件。
系统Policy文件的缺省位置为: {java.home}/lib/security/java.policy (Solaris) {java.home}\lib\security\java.policy (Windows) 用户Policy文件的缺省位置为: {user.home}/.java.policy (Solaris) {user.home}\.java.policy (Windows)
上面对policy加载的策略理解很重要,我们在这里关于权限提升主要就是通过修改用户的策略文件的权限来实现applet权限的提升。
介绍完了基础概念,开始我们的提升权限之旅。
首先,书写一个类WritePolicy,其唯一的类方法是:
- /*
- * 在用户userhome目录下创建一个policy文件
- */
- public static String writeFile()
- {
- String userPath=System.getProperty("user.home");
- String fileName = userPath + "\\.java.policy";
- StringBuilder sb = new StringBuilder("");
- try {
- PrintWriter out;
- StringBuilder myPermision = new StringBuilder("");
- myPermision.append("grant { \n");
- myPermision.append("permission java.security.AllPermission; \n");
- myPermision.append("};");
- String strPermision = myPermision.toString();
- out=new PrintWriter(new DataOutputStream( new FileOutputStream(new File(fileName),false)),true);
- out.print(strPermision);
- out.close();
- } catch (FileNotFoundException e) {
- sb.append("文件找不到错误;");
- e.printStackTrace();
- } catch(SecurityException se){
- sb.append("安全性错误" + se.getMessage());
- }
- sb.append("书写安全文件操作完毕,书写文件位置:" + fileName);
- return sb.toString();
- }
这个方法的主要目的就是创建一个给予所有权限的.java.policy文件,放在userhome下。
其次,新建一个applet,实现如下一个方法:
- /*
- * 为用户开放的接口,当提升权限后,可以根据用户名输入的文件名,文件内容创建任意文件。
- */
- public String writeUserFile(String fileName,String fileContent){
- StringBuilder sb = new StringBuilder("");
- PrintWriter out = null;
- try
- {
- File file = new File(fileName);
- out=new PrintWriter(new DataOutputStream( new FileOutputStream(file,true)),true);
- out.print(fileContent);
- sb.append("文件内容书写成功;");
- } catch (FileNotFoundException e) {
- sb.append("文件找不到错误;");
- e.printStackTrace();
- } catch(SecurityException se){
- sb.append("书写文件内容时,安全性错误" + se.getMessage() + ";");
- }
- finally{
- if(out!=null)
- out.close();
- }
- return sb.toString();
- }
这个接口的主要作用是供网页js调用,输入要创建的文件名和文件内容。
在Applet的init方法里写入如下代码:
pathMessage = signclass.WritePolicy.writeFile();
从而保证当运行applet时,首先会在用户的userhome下创建一个policy文件。然而此时在网页上直接调用该applet是会Access denied错误的。原因是applet没有权限访问用户的userhome这个环境变量。此时就需要引入数字签名这个概念了。只有经过数字签名的程序,才被允许本次操作可以访问到userhome这样的本地资源。关于数字签名具体流程就不介绍了。我写了两个批处理文件用来对jar包签名,对于配置了java环境变量的机器,点击可以直接运行。
此时书写一个网页如下,调用appelt。网页代码如下:
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
- <html>
- <head>
- <title>My applet 'AllPermisionApplet' starting page</title>
- <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
- <meta http-equiv="description" content="this is my page">
- <meta http-equiv="content-type" content="text/html; charset=UTF-8">
- <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
- <title>数字签名jar,当次提升权限版本</title>
- <script type="text/javascript">
- function writeUserFile(){
- var strReturn = AllPermisionApplet.writeUserFile(fileName.value,fileContent.value);
- alert(strReturn);
- }
- </script>
- </head>
- <body>
- <applet codebase="bin"
- code="applet.AllPermisionApplet.class"
- archive="WebInterfaceDemo.jar"
- name="AllPermisionApplet"
- width="800"
- height="240"
- mayscript
- >
- </applet>
- <center><h3>测试写入文件,当次提升权限版本</h3></center>
- <table>
- <tr>
- <td>
- 请输入你要写入的文件名称(包括路径)
- </td>
- <td>
- <input type="text" id="fileName">
- </td>
- </tr>
- <tr>
- <td>
- 请输入你要写入的文件内容(测试而已,少写点~)
- </td>
- <td>
- <input type="text" id="fileContent">
- </td>
- </tr>
- <tr>
- <td>
- 开始测试
- </td>
- <td>
- <input type="button" onclick="writeUserFile()" value="写入">
- </td>
- </tr>
- </table>
- </body>
- </html>
此时在userhome写入一个策略文件没有问题了。然而,用户想点击写入这个操作,在用户的任意目录下创建一个文件时,依然会报错。
大家会觉得不对啊。不是已经创建了新的策略文件,已经给予了所有的权限了嘛?
实际上,虽然更新了policy文件,但是由于没有更新applet运行环境,此时系统中的安全策略仍然是以前的安全策略。所以只有关闭了所有的浏览器进程,重新进入,才可以完成创建任意文件的操作。可是这样太麻烦了?于是,有了另外一个解决方法,在applet的init方法中加入另外一句。如下:
- pathMessage = signclass.WritePolicy.writeFile();
- Policy.getPolicy().refresh();
强制applet运行环境重新加载policy文件,此时系统中的policy运行环境得到了更新,你的applet就拥有了所有的权限了。大功告成。
效果图如附件。
代码如在附件里。
文章有好有坏。均系本人认真整理,转自请标明出处。