Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1562212
  • 博文数量: 3500
  • 博客积分: 6000
  • 博客等级: 准将
  • 技术积分: 43870
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-03 20:31
文章分类

全部博文(3500)

文章存档

2008年(3500)

我的朋友

分类:

2008-05-04 19:25:14

一起学习

一、背景介绍

1.Seal简介
Seal是Java 2开发平台引入的一个新的安全特性。众所周知,在Unix下,当前目录不要轻易加入到PATH环境变量中去,否则黑客可以写一个文件名等同于系统命令的执行程序放在用户的目录下,从而使用户在自己目录下执行系统命令时落入圈套。同样,由于Java的开放性,黑客可以写一个具有同样名称的包,并将此包放在CLASSPATH的最前面。由于JAVA虚拟机是根据包在CLASSPATH中的排列顺序决定优先顺序的,所以如果用户需要调用这个名称的包,则将又落入圈套。

抛开黑客不说,在现实软件环境中,很有可能一个包的新旧版本共存在CLASSPATH中,这样如果新旧版本存在某些差异,则将带来不可预知的结果。这一点也恰恰是为什么微软的Win98用的时间越长就越不稳定的原因。

所以,从JAVA 2开始,Java引入了Seal(加封)安全机制。所有的JAR文件和包都可以选择是否需要加封,如果JAR文件被加封,则等价于JAR文件中的所有包被加封。一旦被加封的包中的某个类被引用,则规定任何以后对这个包中的成员的引用都必须在同一个JAR文件中。从而保证了版本的一致性。如果违反了上述Seal机制,则我们就将遇到Sealing Violation错误。

2.JAXP包与Sealing Violation错误
如果不是因为XML的流行和JAXP的出现,Java程序员中可能不会有太多人遇到上述Sealing Violation错误。首先是因为JDK中加封的包并不多,其次是因为这些加封的包用处并不广,从而很少会出现冲突现象。可是XML和JAXP改变这一切。XML毫无疑问的将会覆盖整个Internet,这样对XML进行Parse是必不可少的功能之一,Sun的JAXP软件包便可以实现对XML,XSL的Parse工作。让我们打开JAXP中jaxp.jar中的META-INF\manifest.mf文件,我们可以看到文件的第一行为:Sealed: true

也就是说,JAXP是加封过的,由此而带来的不可避免的问题就是,几乎任何一位使用JAXP的程序员都会遇到Sealing Violation这个问题。由于Sealing Violation在以往的Java编程中非常少见,这样大量缺少经验的程序员受困与此。

二、错误演示
以下我们将通过一个普通的Java程序来演示Sealing Violation错误的产生的大部分情形。

我们使用的Java程序是JAXP1.1中的一个很简单的范例程序,它的功能是利用XSLT转换XML,源程序如下:



import javax.xml.transform.*

import java.io.*



public class SimpleTransform

{

	public static void main(String[] args)

    throws TransformerException, TransformerConfigurationException, 

           FileNotFoundException, IOException

  {  

	TransformerFactory tFactory = TransformerFactory.newInstance();

	Transformer transformer = tFactory.newTransformer(new StreamSource("test.xsl"));

	transformer.transform(new StreamSource("test.xml"), 

			              new StreamResult(new FileOutputStream("test.out")));

  }

}

注意,虽然上述程序只显式import了javax.xml.transform包,但我们要注意这个程序对其它包的依存关系。在这里,JAXP的Transformer是通过SAX解析器解析XML的,这样在javax.xml.transform内部还要调用org.xml.sax*包。

为了造成冲突,我们使用了James Clark编写的XML解析引擎XT,这样我们的CLASSPATH环境变量如下(省略了jar文件的路径名):
.\; sax.jar; xt.jar; xalan.jar; jaxp.jar; crimson.jar

其中sax.jar和xt.jar属于XT软件包且都没有被加封,剩下三个属于JAXP软件包并且Sealed属性都为True。

现在让我们编译并运行上述范例,命令行的输出为:



Exception in thread "main" java.lang.SecurityException: sealing violation

        at java.net.URLClassLoader.defineClass(Unknown Source)

        at java.net.URLClassLoader.access$100(Unknown Source)

        at java.net.URLClassLoader$1.run(Unknown Source)

        at java.security.AccessController.doPrivileged(Native Method)

        at java.net.URLClassLoader.findClass(Unknown Source)

        at java.lang.ClassLoader.loadClass(Unknown Source)

        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)

        at java.lang.ClassLoader.loadClass(Unknown Source)

        at java.lang.ClassLoader.loadClassInternal(Unknown Source)

        at java.lang.Class.forName0(Native Method)

        at java.lang.Class.forName(Unknown Source)

        at javax.xml.transform.TransformerFactory.newInstance(TransformerFactory.java:146)

        at SimpleTransform.main(SimpleTransform.java:10)

好了,错误出现了,原因很简单,XT的sax.jar中定义了org.xml.sax.*包,而JAXP中的xalan.jar中也定义了这个包,这样当我们的程序调用xalan.jar中的javax.xml.transform.*包时,需要对XML进行解析,这样便去找org.xml.sax包,由于sax.jar排在前面,这样javax.xml.transform.*中对org.xml.sax.*的调用实际上便发生在sax.jar文件里,而这恰恰违反了xalan.jar中Seal的约束。

三、解决方案

1.改变CLASSPATH顺序
改变jar文件在CLASSPATH中的顺序显然是最简单直接的想法。让我们把JAXP和XT换个位置,这样CLASSPATH变量如下:
.\; xalan.jar; jaxp.jar; crimson.jar; sax.jar; xt.jar

然后运行上述程序,OK,顺利通过。

真的就这么简单吗?从本质上来说确实是这样,可在实际编程中,我们还会遇到各种各样的现象,需要我们仔细的去发现背后的原因,让我们来看两个例子:

第一个例子:

既然sax.jar中的org.xml.sax.*是罪魁祸首,那好,让我们把它拿掉。这样CLASSPATH为:
.\; xt.jar; xalan.jar; jaxp.jar; crimson.jar

xt.jar中只有com.jclark.xsl.*包,可是Sealing Violation错误又出现了,为什么?原因当然还是org.xml.sax.*又冲突了。让我们看看xt.jar的meta-inf/manifest.mf文件:
Manifest-Version: 1.0
Main-Class: com.jclark.xsl.sax.Driver
Created-By: 1.2.1 (Sun Microsystems Inc.)
Class-Path: sax.jar

从最后一行我们可以看出,实际上sax.jar文件又被包含了进来。

第二个例子:

将CLASSPATH恢复为正确的格式:
.\; xalan.jar; jaxp.jar; crimson.jar; sax.jar; xt.jar

然后运行Tomcat3.2,结果在jsp和servlet调用上述范例程序中的功能时,又出现了Sealing Violation错误,这个原因同Tomcat有关,以下是Tomcat启动批处理文件中的几行:
if exist "%TOMCAT_HOME%\lib\ant.jar" set CP=%CP%;%TOMCAT_HOME%\lib\ant.jar
if exist "%TOMCAT_HOME%\lib\jasper.jar" set CP=%CP%;%TOMCAT_HOME%\lib\jasper.jar
if exist "%TOMCAT_HOME%\lib\jaxp.jar" set CP=%CP%;%TOMCAT_HOME%\lib\jaxp.jar
if exist "%TOMCAT_HOME%\lib\parser.jar" set CP=%CP%;%TOMCAT_HOME%\lib\parser.jar
if exist "%TOMCAT_HOME%\lib\servlet.jar" set CP=%CP%;%TOMCAT_HOME%\lib\servlet.jar
if exist "%TOMCAT_HOME%\lib\webserver.jar" set CP=%CP%;%TOMCAT_HOME%\lib\webserver.jar
:chkClasspath
if "%CLASSPATH%" == "" goto noClasspath
set CP=%CP%; %CLASSPATH%

好了,这样上述批处理命令的最后一行将Tomcat自己的jar文件加了进去,由于Tomcat3.2带的jaxp.jar还没有包含javax.xml.transform包,这样仍然使用的是后面的在CLASSPATH中的jaxp.jar,而这时Tomcat的parser.jar又扮演了冲突的角色,因为它定义了org.xml.sax.*。这种情况下的解决方法就是改动上述批处理文件,将CLASSPATH提前,即如下改动上述最后一句:
set CP=%CLASSPATH%; %CP%

从以上两个例子我们可以看出,虽然原因很简单,可很有可能被表面现象所隐藏,这就需要我们去考虑每个可能造成这个错误的地方。

2.更改JAR文件的Seal属性
这个解决方法看起来很暴力,直接将JAR文件中的meta-inf/manifest.mf中的Sealed:true改成Sealed:false。这种方法不但增加了安全隐患而且移植性差,你不但需要将你修改过的JAXP包随自己的软件包一块发布,而且还要保证它们列在CLASSPATH的最前面。这是下策,可是有时候又不得不如此,这一点恐怕Tomcat最有体会,因为Tomcat4.0就是采用了这种方法,以下是Tomcat4.0的Release-Notes-4.0.txt中的一段话:

WARNING: Tomcat 4.0 ships with a modified version of the JAXP/1.1 "jaxp.jar" and "crimson.jar" files from JAXP/1.1 final release. The "sealed" attribute has been removed from the manifest file for these two JARs, to avoid "package sealing violation" errors that were caused by them in a JDK 1.3 environment. You MUST NOT replace these files with a different (or later) release of JAXP, unless that later release has had the sealed attribute removed, or you will encounter "package sealing violation" errors when trying to use a different XML parser in a web application.

3.升级JDK
虽然JDK1.4现在还只是Beta版,可如果你喜欢这种解决方式的话,你可以安装JDK1.4 beta,在JDK1.4中,这个问题得到了解决。我并不太清楚JDK1.4对这个问题的解决方法,不过我猜想最有可能的方法是对CLASSPATH中Seal过的包进行优先处理,这样用户就无需考虑顺序问题。

四、总结
事实上,绝大部分关于JAXP的Sealing Violation的问题都是由于存在org.xml.sax.*这个包的多个实现,不仅仅是上面提到的两个JAR文件,还有j2ee.jar,xml.jar等。由此可见,Sun在加封JAXP时缺乏全盘的考虑。无论如何,从JDK1.4 beta版的情况来看,这个错误已经得到了Sun的重视,希望在不久的将来我们看到这个问题的完美解决。

参考资料

  • JAXP主站点
  • XT主站点
  • Tomcat主站点

下载本文示例代码


Sealing Violation错误模式Sealing Violation错误模式Sealing Violation错误模式Sealing Violation错误模式Sealing Violation错误模式Sealing Violation错误模式Sealing Violation错误模式Sealing Violation错误模式Sealing Violation错误模式Sealing Violation错误模式Sealing Violation错误模式Sealing Violation错误模式
阅读(802) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~