操作数字签名逾越Java Applet的安详限制
副标题#e#
Java技能之所以在本日获得了如此辽阔的应用,个中它的安详性是不能不提的。差异于其它技能(譬喻Microsoft的ActiveX)中安详性作为附加设计和补丁,Java从设计之初便思量到了安详性。因此Java的安详性是在语言条理实现的。Java的安详性由下列三个方面担保:
1、语言特性(包罗数组的界线查抄、范例转换、打消指针型变量)。
2、资源会见节制(包罗当地文件系统会见、Socket毗连会见)。
3、代码数字签名(通过数字签名来确认代码源以及代码是否完整)。
本文主要接头团结后两种技能来实现逾越Applet的安详限制。我们先来看一下这三个方面的详细实现。我们知道Java的原代码是先编译成为一种字节码的中间代码,存放这种代码的文件就是.class的文件。真正执行的时候是将class文件装载到JVM(虚拟机)中,然后由JVM表明执行的。所以数组的上下界查抄及正当的范例转换是通过JVM获得担保的。
Java通过一个类装载器类(ClassLoader)将虚拟机代码文件(即class文件)装载到JVM中,当完成装载后,一个被称做安详打点器(SecurityManager)的类开始运行,这就是上面描写的第二个方面的实现。譬喻当一个Applet的class文件被缺省的类装载器装载到JVM中后,JVM会当即为它装载一个SecurityManager的子类AppletSecurity,由这个打点器来验证操纵。代码的所有行动(譬喻文件读写)都要先颠末验证,只有被该安详打点器接管的行动才气完成,不然就会抛出SecurityException异常。那么安详打点器类是怎么判定代码的权限的呢?这就是操作Policy文件。
对付JDK1.0,权限被笼统的分别为两大块。一是拥有所有的权限,一个是仅拥有"沙箱"(sandBox)权限,这也是普通的Applet所拥有的权限。这时当地文件读写或是与源主机(Orignal Server)以外的主机毗连都是被克制的。这种分另外最大问题就是缺乏机动性。譬喻我们但愿一个Applet在用户信任的环境下可以或许对当地文件系统的某个目次举办读写,但并不要通过Socket与其它主机毗连。这是JDK1.0的权限分别就不能到达要求。JDK1.1后改造了权限的分别,引入了权限集(PermissionSet)的观念。它细划了权限的放放面面,你可以有选择性的组合你需要的权限来到达非凡的要求。下图显示了这种分别:
图1
图一中的BasicPermission还可以进一步细分为更多的细节权限,譬喻:AWTPermission、RuntimePermission等等。Java通过一个后缀名为.policy的文件来组合这些权限。安装完JRE(Java Runtime Environment)后有两个缺省的权限文件,它们是:
${java.home}/lib/security/java.policy
${user.home}/.java.policy
#p#副标题#e#
下面是一个java.policy文件的实例:
// Standard extensions get all permissions by default
grant codeBase "file:${java.home}/lib/ext/*" {
permission java.security.AllPermission;
};
// default permissions granted to all domains
grant {
// Allows any thread to stop itself using the java.lang.Thread.stop()
// method that takes no argument.
// Note that this permission is granted by default only to remain
// backwards compatible.
// It is strongly recommended that you either remove this permission
// from this policy file or further restrict it to code sources
// that you specify, because Thread.stop() is potentially unsafe.
// See "http://java.sun.com/notes" for more information.
permission java.lang.RuntimePermission "stopThread";
// allows anyone to listen on un-privileged ports
permission java.net.SocketPermission "localhost:1024-", "listen";
// "standard" properies that can be read by anyone
permission java.util.PropertyPermission "java.version", "read";
permission java.util.PropertyPermission "java.vendor", "read";
permission java.util.PropertyPermission "java.vendor.url", "read";
permission java.util.PropertyPermission "java.class.version", "read";
permission java.util.PropertyPermission "os.name", "read";
permission java.util.PropertyPermission "os.version", "read";
permission java.util.PropertyPermission "os.arch", "read";
permission java.util.PropertyPermission "file.separator", "read";
permission java.util.PropertyPermission "path.separator", "read";
permission java.util.PropertyPermission "line.separator", "read";
permission java.util.PropertyPermission "java.specification.version", "read";
permission java.util.PropertyPermission "java.specification.vendor", "read";
permission java.util.PropertyPermission "java.specification.name", "read";
permission java.util.PropertyPermission "java.vm.specification.version", "read";
permission java.util.PropertyPermission "java.vm.specification.vendor", "read";
permission java.util.PropertyPermission "java.vm.specification.name", "read";
permission java.util.PropertyPermission "java.vm.version", "read";
permission java.util.PropertyPermission "java.vm.vendor", "read";
permission java.util.PropertyPermission "java.vm.name", "read";
};
由上面的这个文件可以看出,所有policy文件的写法都是雷同下面的名目:
grant codesource
{
permission_1;
permission_2;
}
#p#分页标题#e#
个中permission_1代表一个详细的权限描写,这里我们只来看看关于文件权限的描写,其它的权限描写是雷同的。
写法 | 代表寄义 |
file | 一个指定的文件 |
directory/ | 一个指定的目次 |
dirctory/* | 一个目次下的所有文件 |
dirctory/- | 指定目次及子目次的所有文件 |
– | 当前目次及子目次的所有文件 |
* | 当前目次的所有文件 |
<<ALL FILES>> | 整个文件系统 |
表1
下面是几个详细的例子:
grant
{
permission java.io.FilePermission "<<ALL FILES>>" "read,write";
};
grant
{
permission java.io.FilePermission "<<${user.home/-} >>" "read,write,delete";
};
光有policy文件照旧不足,客户无法判定此刻执行的代码是否是由你宣布的,也不能担保这个代码在传输的进程中有没有被人给恶意的粉碎。所以还需要数字签名技能来担保这两方面。JDK中给我们提供了几个东西来完成这些事情。
团结这几种技能就可以到达本文的目标了,下面就是本文的方针代码,它是一个可以读取当地文件系统的Applet:
代码1
/-------------------------------------
package jcomponent;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.io.*;
public class FileReaderApplet extends Applet {
boolean isStandalone = false;
TextField fileNameField;
TextArea fileArea;
file://Get a parameter value
public String getParameter(String key, String def) {
return isStandalone ? System.getProperty(key, def) :
(getParameter(key) != null ? getParameter(key) : def);
}
file://Construct the applet
public FileReaderApplet() {
}
file://Initialize the applet
public void init() {
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
file://Component initialization
private void jbInit() throws Exception {
this.setSize(new Dimension(400,300));
this.setLayout(new BorderLayout());
Panel panel=new Panel();
Label label=new Label("File Name");
panel.add(label);
fileNameField=new TextField(25);
panel.add(fileNameField);
Button b=new Button("Open File");
b.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
loadFile(fileNameField.getText());
}
});
panel.add(b);
this.add(panel,BorderLayout.NORTH);
fileArea=new TextArea();
this.add(fileArea,BorderLayout.CENTER);
}
public void loadFile(String fileName){
try{
BufferedReader reader=new BufferedReader(new FileReader(fileName));
String context=new String();
while((context=reader.readLine())!=null){
fileArea.append(context+"/n");
}
reader.close();
}catch(IOException ie){
fileArea.append(ie.getMessage());
}catch(SecurityException se){
fileArea.append("because of security constraint ,it can not do that!");
}
}
file://Get Applet information
public String getAppletInfo() {
return "This is an applet can read and write the local file system";
}
}
#p#分页标题#e#
假如你将这个代码嵌入网页中并执行它,当你试图打开一个当地文件时就会产生SecurityException。各人随着我举办下面的步调就可以最终拥有读写文件的权限。在此之前你需要有以下的东西:JDK1.1以上、JRE、HTMLConvert。这些东西在SUN的Java站点上都有,并且也是免费的。将它们别离安装好,我们将所有涉及的文件都放在c:/admin中。
步调一:(打包class文件)
在呼吁行中执行以下的语句:jar -cvf MyApplet.jar class
留意这里的所有.class文件均是放在一个class的目次中的。本步调执行完毕后,将在c:/admin中发生一个名为MyApplet.jar的文件。
步调二:(在网页中嵌入Applet)
这个网页的名字叫做FileReaderApplet.html,下面是嵌入Applet部门的写法:
<APPLET
CODEBASE = "."
CODE = "jcomponent.FileReaderApplet.class"
ARCHIVE ="MyClass.jar"
NAME = "TestApplet"
WIDTH = 400
HEIGHT = 300
HSPACE = 0
VSPACE = 0
ALIGN = middle
>
</APPLET>
完成这个步调后,这个Applet已经可以显示了。可是还不能读写当地的文件系统。
步调三:(生成证书及签名)
请在呼吁行情况下执行以下的呼吁:
1、keytool -genkey -keystore pepper.store -alias pepper
这个呼吁用来发生一个密匙库,执行完毕后应该在c:/admin中发生一个pepper.store的文件,这里的pepper是我本身的名字,你可以对它举办修改。别的在执行呼吁的时候尚有提示你输入密匙库的暗码,这里你必然要记着,不然后头要用的时候无法输入。
2、keytool -export -keystore pepper.store -alias pepper -file pepper.cert
这个呼吁用来发生签名时所要用的证书,同样这里的pepper也可以换成你本身需要的名字。这个呼吁执行完后在c:/admin中发生一个pepper.cert的文件。
4、jarsigner -keystore pepper.store MyApplet.jar pepper
这个呼吁用上面发生的证书将我们的jar文件举办了签名。
步调四:(修改文件)
1、在c:/admin中发生一个名为applet.policy的文件,其内容如下:
keystore "file:c: /admin/pepper.store", "JKS";
grant signedBy "pepper"
{ permission java.io.FilePermission "<<ALL FILES>>", "read";
};
这个文件让由pepper签名的Applet拥有当地所有文件的读权限。
2、修改${java.home}/jre/lib/security目次下的java.security,找到下面这两行:
policy.url.1=file:${java.home}/lib/security/java.policy
policy.url.2=file:${user.home}/.java.policy
在下面添写第三行
policy.url.3=file:c: /admin/applet.policy
完成这个修改后我们在前面建设的applet.policy文件才有效。
步调五:(转换html文件)
运行前面提到的HTMLConvert东西,将原有的FileReaderApplet.html转化成下面的形式:
<!--"CONVERTED_APPLET"-->
<!-- CONVERTER VERSION 1.3 -->
<OBJECT classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
WIDTH = 400 HEIGHT = 300 NAME = "TestApplet" ALIGN = middle VSPACE = 0 HSPACE = 0 codebase="http://java.sun.com/products/plugin/1.3/jinstall-13-win32.cab#Version=1,3,0,0">
<PARAM NAME = CODE VALUE = "jcomponent.FileReaderApplet.class" >
<PARAM NAME = CODEBASE VALUE = "." >
<PARAM NAME = ARCHIVE VALUE = "MyApplet.jar" >
<PARAM NAME = NAME VALUE = "TestApplet" >
<PARAM NAME="type" VALUE="application/x-java-applet;version=1.3">
<PARAM NAME="scriptable" VALUE="false">
<COMMENT>
<EMBED type="application/x-java-applet;version=1.3" CODE = "jcomponent.FileReaderApplet.class" CODEBASE = "." ARCHIVE = "MyApplet.jar" NAME = "TestApplet" WIDTH = 400 HEIGHT = 300 ALIGN = middle VSPACE = 0 HSPACE = 0 scriptable=false pluginspage="http://java.sun.com/products/plugin/1.3/plugin-install.html"><NOEMBED></COMMENT>
</NOEMBED></EMBED>
</OBJECT>
<!--
<APPLET CODE = "jcomponent.FileReaderApplet.class" CODEBASE = "." ARCHIVE = "MyApplet.jar" WIDTH = 400 HEIGHT = 300 NAME = "TestApplet" ALIGN = middle VSPACE = 0 HSPACE = 0>
</APPLET>
-->
<!--"END_CONVERTED_APPLET"-->
各人不要看到这里的写法很巨大,可是这些都是由HTMLConvert东西自动实现的。这个东西有呼吁行和图形界面两种运行方法。
#p#分页标题#e#
好了,此刻这个Applet可以运行读写文件的成果了。假如你要思量在Internet上实现这个Applet,那么你也不需要在所有的客户端均做上面的步调,你只需要在你的处事器上建设一个目次,譬喻c:/admin,将这个目次映射为www.testApplet.com/admin。这里的www.testApplet.com是一个假定的网址,将pepper.cert、pepper.store、FileReaderApplet.html、MyApplet.jar以及applet.policy放在这个目次中,然后修改applet.policy文件如下:
keystore "http:// www.testApplet.com/admin/pepper.store", "JKS";
grant signedBy "pepper"
{ permission java.io.FilePermission "<<ALL FILES>>", "read";
};
3、而每个客户端仅仅需要修改一下它们的${java.home}/jre/lib/security目次下的java.security文件如下:
policy.url.1=file:${java.home}/lib/security/java.policy
policy.url.2=file:${user.home}/.java.policy
policy.url.3= http:// www.testApplet.com/admin/applet.policy
虽然每个客户端照旧需要安装JRE的,不外此刻的欣赏器安装时都已经自动安装了。