刚刚开始学JVM,写点东西,就当时笔记吧
Java的安全模型
关于Java的安全模型,《深入Java虚拟机》中有如下的解释:
Java安全模型侧重于保护终端用户免受从网络下载的、来自不可靠的来源的、恶意程序(以及善意程序中的bug)的侵犯。为了达到这个目的,Java提供了一个用户可配置的“沙箱”,在沙箱中可以放置不可靠的Java程序。沙箱对不可靠的活动进行了限制,程序可以在沙箱的安全边界内做任何事,但是不能进行任何跨越这些边界的举动。......因为沙箱安全模型对不可靠代码能做什么、不能做什么进行了严格的控制,所以用户可以相对安全地运行不可靠代码。
所以说Java安全模型的核心就是“沙箱”,沙箱由以下几部分构成:
- 类装载器结构。
- class文件检验器。
- 内置于Java虚拟机(及语言)的安全特性。
- 安全管理器及Java API
其中类装载器体系结构是沙箱中的第一道防线。
类装载器体系结构
类装载器(class loader),又叫类加载器,负责加载 Java 类的字节代码到 Java 虚拟机中。类装载器体系结构在三个方面对Java的沙箱起作用:
- 它防止恶意代码去干涉善意的代码。
- 它守护了被信任的类库的边界。
- 它将代码归入某类(称为保护域),该类确定了代码可以进行哪些操作。
暂时先说明如何实现前两条性质。
1.防止恶意代码去干涉善意的代码
通过命名空间可以防止恶意代码,每个类装载器都有一个命名空间。不同命名空间的程序不能相互访问,同名的类通过加载到不同的命名空间来区别。如上图所示,有两个相同名字的类A,它们被装载到了不同的类装载器中。假设深色的A为恶意代码,除非被授权可以访问其他装载器中的类,否则不能访问浅色的A。还有一点,如果B要使用A的某个方法,则B使用的深色的A中的方法。
2.守护被信任的类库的边界
类装载器体系结构守护了被信任的类库的边界,这是通过分别使用不同的类装载器装载可靠的包和不可靠的包来石像的。虽然通过赋给成员受保护(或包访问)的访问限制,可以在同一个包中的类型间授予彼此访问的特殊权限,但这种特殊的权限只能授权在同一个包(命名空间?)中的运行时成员,而且他们必须是由同一个类装载器装载的。
类装载器的结构如上图所示,分为两种:系统提供三个主要装载器,其它的装载器(为了更好的区别,用户的装载器写成加载器,其实都是一个东西)可以由用户自己编写,但是要保证每个装载器(除了启动类装载器)都有一个父类装载器。三个主要装载器分别是
- 启动类装载器(bootstrap class loader):用来装载Java的核心库。主要是指Java API提供的基本class文件。
- 标准扩展类装载器(extensions class loader):用来装载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
- 类路径装载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来装载 Java 类。一般来说,Java 应用的类都是由它来完成装载的。可以通过
ClassLoader.getSystemClassLoader()
来获取它。
装载流程为:
- 假设用户自定义加载器1要装载一个class文件,首先要向它的父类发出请求。
- 如果类路径装载器没在类路径上找到这个class文件,则继续向它自己的父类发出请求,否则,直接装载。
- 如果标准扩展类装载器没有在扩展库中找到,则继续向它自己的父类发出请求,否则,直接装载。
- 如果启动类装载器没有在API中找到class文件,则返回,表示用户自定义加载器可以装载class文件。否则,直接装载。
这样做可以保证安全。举例来说,假设有一个java.lang.String类,这个类是一个从别处得到的类,其中可能含有某些恶意代码。用户自定义加载器1要装载这个类,则需要先向它的父类的发出请求,其父类再向其父类的父类发出请求,直到启动类装载器在Java API中找到一个同名的java.lang.String类并装载这个API中的String类,请求终止。所以其实恶意的String类并没有被装载,程序以后使用的String类都是API中的String类。
类装载器中还有一个机制可以保证安全,那就是:如果一个类想要访问另一个类,除非被授权,否则只有处于同一个包(命名空间?)中且被同一个装载器装载才能互相访问。假设有一个java.lang.Virus类,按照上面的步骤装载,最后Virus会被用户自定义加载器装载,而其它java.lang中的类则都被启动类装载器装载,所以Virus不能java.lang包中的任何一个类。
类装载器还有另一种方法来保护被信任的类库的边界,简单来说就是可以拒绝装载特定的禁止类型。比如说,比如类路径中有一个包absolutepower,用户自定义加载器装载不想装载类路径中的类。有一个请求要求用户自定义加载器装载absolutepower.FancyClassLoader类,通过检查类名可以得知它是来自类路径中的类,则用户自定义加载器立即抛出一个异常。
总结
总之保证安全有三点:
- 不是同一命名空间的类之间不能相互访问。
- 能用父类装载器装载的类尽量用父类装载。
- 不是同一装载器装载的类之间不能互相访问。