论坛登陆 用户: 密码:
联系我们
设为首页
加入收藏
业界新闻 网络编程 程序开发 网页图象 聊天通讯 软件应用 网络安全 硬件学堂 教育频道 站长club

利用数字签名超越java applet的安全限制


 日期:2005-7-18 8:53:22     来源:易特网络技术   编辑:黑鹰  点击:

  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

  下面是一个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;
}

  其中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";
}

}

  如果你将这个代码嵌入网页中并执行它,当你试图打开一个本地文件时就会发生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工具自动实现的。这个工具有命令行和图形界面两种运行方式。

  好了,现在这个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的,不过现在的浏览器安装时都已经自动安装了。


上一篇:怎样设计合适的接口
下一篇:没有了
[发送给好友] [打印本页] [关闭窗口] [返回顶部转载请注明来源:http://www.iyit.net
特别声明: 本站除部分特别声明禁止转载的专稿外的其他文章可以自由转载,但请务必注明出处和原始作者。文章版权归文章原始作者所有。对于被本站转载文章的个人和网站,我们表示深深的谢意。如果本站转载的文章有版权问题请联系编辑人员,我们尽快予以更正。
责任编辑: 黑鹰 投稿作者: 易特网络
信息来源: 易特网络技术 录入时间: 2005-7-18 8:53:22
浏览次数: 投稿信箱: shtghy@163.com
设置首页 - 版权声明 - 广告服务 - 关于我们 - 联系我们 - 友情连接
copyrights ©2004-2005 iyit.net all rights reserved. 网站合作、广告联系qq:147007642、466949678
易特网络技术 点击这里给我发消息