安全模型简介

安全模型使Java成为网络环境的技术,因为它们建立了对网络移动代码安全执行的必要的可信机制。

Java安全模型侧重于保护终端用户免受从网络下载的、来至于不可靠来源的、恶意程序的侵犯。而“沙箱”机制成为了这一目的的支持机制,在“沙箱”中存放不可信的Java程序。“沙箱”对不可靠的程序的活动进行了限制,程序可以在“沙箱”的安全边界内做任何事,但是不能进行任何跨越这些边界的举动。

比如说,在版本1.0中的沙箱对于很多不可靠的applet进行了如下限制:

a. 对本地硬盘的读写

b. 进行任何网络连接,但是不能连接到提供这个applet的源主机

c. 创建新的进行

d. 装载新的动态链接库

但是,基于版本1.0的沙箱模型过于严格,有些善意(但是不可靠)的代码常常无法进行有效的工作,所以,在版本1.1,“沙箱”模型得到了改进,引入了基于代码签名和认证的信任模型。

基本沙箱

Java沙箱的基本组成组件有:

1.类加载器结构

2.Class文件检验器

3.内置于Java虚拟机的安全特性

4.安全管理器及Java API

其中最重要的特点是: 组件当中的类加载器以及安全管理器是可以由用户定制的。

起到第一道安全保障作用的"双亲委派类加载模型"

双亲委派方式的类加载,指的是优先从顶层启动类加载器开始,自顶向下的方式加载类的模型(参见第一条类装载器体系结构)。

这种模型的好处是,底层的类装载器装载的类无法与顶层类装载器装载的类相互调用。
哪怕是同包下的类,只要他们不属于同一类装载器,都是相互隔绝的。这对一些有安全隐患的类起到了安全隔离的作用。使它不能冒充系统类来破坏程序正常运作。

此外,不同的类装载器,也有自己的类装载范围。比如启动类装载器,它只会装在jdk/lib目录下的包/类,因此,系统级的类是相对安全的。
 

 

class文件校验器,通过四趟扫描,保证了class文件正确

第一趟是,在类被加载时进行,检查class文件的结构是否正确。比较典型的就是,检查class文件是否以魔数OxCAFEBABE打头。
通过这趟检查,可以过滤掉大部分可能损坏的,或者压根就不是class的文件,来冒充装载。
 
第二趟是,在连接过程中进行,称为类型数据的语义检查,检查它是否符合java语言特性里的编译规则。比如发现一个类的超类不是Object,就抛出异常。检查每个方法描述符是否符合特定的语法、格式。
 
第三趟是,在连接过程中进行,称为字节码验证,检查字节码是否能被JVM安全的执行,而不会导致JVM崩溃。 字节码流代表了java的方法,它是由称为操作码的单字节指令组成的序列,每一个操作码后都跟着一个或多个操作数。操作数用于在java虚拟机执行操作码指令时提供所需的额外的数据。执行字节码时,依次执行每个操作码,这就在java虚拟机内构成了执行的线程。每一个线程被授予自己的java栈,这个栈是由不同的栈帧构成的。每一个方法调用将获得一个自己的栈帧(也就是一个方法对应一个栈帧)——栈帧其实就是一个内存片断,其中存储着方法中的局部变量和计算的中间结果。用于存储方法中间结果的部分称为该方法的操作数栈。在执行一个操作码时,除了可以使用紧随其后的操作数,虚拟机还可以使用操作数栈中的数据,或局部变量中的数据。
 
第四趟是,符号引用验证。是在动态链接时进行,一个类文件,它会包含它引用的其他类的全名和描述符,并跟他们建立符号引用(一种虚拟的,非物理连接的方式)。当程序第一次执行到需要符号引用的位置时,jvm会检查这个符号链接的正确性,然后建立真正的物理引用(直接引用)。由于第四趟扫描必须检查被检测的class文件以外的其他类,所以这次扫描可能需要装载新的类。 动态连接是将符号引用解析为直接引用的过程。当java虚拟机执行字节码时,如果它遇到一个操作码,这个操作码在第一次使用一个指向另一个类的符号引用,那么虚拟机就必须解析这个符号引用。在解析时虚拟机执行两个基本任务:1.查找被引用的类(如果必要的话就装载它)。2.将符号引用替换为直接引用,例如一个指向类、字段或方法的指针或偏移量。
 

jvm类型安全特性

这些都是基础的java语言特性,他们降低了java程序出现内存混乱,崩溃的几率。
  • 结构化内存访问(不使用指针,一定程度上让黑客无法篡改内存数据)
  • 自动垃圾收集
  • 数组边界检查
  • 空引用检查
  • 数据类型安全
 

Java api的安全管理器 securityManager

这是安全沙箱中,离我们程序员最接近的一环。
securityMananger,是一个api级别的,可自定义的安全策略管理器,它深入到java api中,在各处都可以见到它的身影。比如SecurityClassLoader。
 
默认情况下,java应用程序是不设置 securityManager 实例的(意味着不会起到安全检查),这个实例需要我们在程序启动时通过 System.setSecurityManager 来设置。
 
一般情况下,检查权限是,通过 SecurityManager.checkPermission(Permission perm) 来完成的。外部程序通过,创建Permission实例,传递给前面的check。
 
Permission是一个抽象类,需要继承它实现不同的权限验证,比如 FilePermission,代表对某个文件的读写权限。
new FilePermission("test.txt", "read")
你可以将这个实例,扔给 SecurityManager,检查是否可读text.txt这个文件。
 

java签名/证书机制

java签名/证书机制,可以保障使用者,安全地调用外部提供的jar,防止你信任的jar被篡改。
 
首先,java的签名,必须是基于jar包的。也就是说,你必须将你要提供的class,打包到jar里。
然后,通过 java 提供的签名工具(jarsigner)对jar包进行签名,发布。
 
签名原理:
使用非对称算法,生成一对公钥/私钥。
 

证书
证书是在签名基础上,对签名值,再进一步做一次加密。而这次加密使用的私钥和公钥都是证书机构提供的。
这种方式,是为了防止,有些恶意用户,在公钥发到你手上前,就对其做了手脚,然后再发一个动过手脚的jar给你,用动过手脚的公钥解动过手脚的jar包,是可以解开的。
而使用证书后,它会对已经加密的签名值,再做一层加密,这样,到你手里,你只需要通过证书机构的公钥进行解密,然后再用jar包发布者的公钥解密就行了。(只能在一定程度上,提供一些安全性)

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐