类装载器体系结构是Java虚拟机安全保证的第一道防线,毕竟是由类装载器将代码,可能是恶意代码或是有漏洞的代码装载入Java虚拟机。
我们看看类装载器是通过什么方式来保证安全的。
1. 首先,不同的类装载器装载的类是被放入不同的命名空间。命名空间由一系列唯一的名称组成。
命名空间是如何完成安全的实现呢?
在Java虚拟机中,在同一个命名空间内的类可以直接进行交互,而不同的命名空间中的类甚至不能察觉彼此的存在。假设一个恶意的类被允许访问其他类加载器加载的类,他就可以潜在的知道一些它不应该知道的信息。
2.第二
类加载器在加载类的过程,被称作双亲委派模式。除启动类装载器以外的每一个类装载器,都有一个“双亲”类装载器。当某个类装载器试图以常用方式装载某个类之前,它会先默认的将这个任务委派给他的双亲,他的双亲再委派给自己的双亲,委派过程一路向上,直到启动器类装载器。
类装载器的委派链如下:
启动类加载器---标准扩展类装载器---类路径类装载器---自定义类装载器
启动类装载器:负责装载核心Java API,JAVA_HOME\lib或者-Xbootclasspath参数指定的路径。
标准扩展类装载器:负责装载来自于任何已安装扩展的class文件。
类路径类装载器:负责加载用户类路径上(ClassPath)上所指定的类库
假设某个Java应用程序启动时,系统会实例化两个装载器:一个扩展类装载器,一个类路径装载器。这两个装载器和启动类装载器一起联入双亲-孩子关系链中。
其中类路径装载器又被成为系统类装载器,是新的用户自定义类装载器的默认双亲。
使用类装载器如何完成安全的实现呢?下面是两种情况
1. 假设我们自定义的类装载器要装在一个java.lang.Integer试图替换一个Java API中同名的类。它能成功吗?自定义加载器在加载前会默认先委派给他的双亲,一路向上直到启动类加载器,当启动类加载器找到一个java.lang.Integer他会被启动类加载器加载,而我们要加载的那个“假”的java.lang.Integer不会有机会被加载到
2. 再假设一种,我们想在一个被信任的包中插入一个全新的类型,比如java.lang.Virus,如果他能被安装到java.lang下,那么他就可以自由访问java.lang下的其他类,从而达到不可告人的目的。自定义加载器在加载前会默认先委派给他的双亲,一路向上直到启动类加载器,一路都没有加载器能加载这个类,所以最后自定义加载器自己去加载。类加载器机制可以防止这个代码得到访问java.lang包中被信任类的访问权限,因为Java虚拟机只把彼此访问的特殊权限授予由同一个类装载器装载到同一个包中的类型。