`
yefeng_laixi
  • 浏览: 15719 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

深入java虚拟机读书笔记——第三章 安全

阅读更多

1.       组成Java沙箱的基本组件如下

A类加载体系结构

Bclass文件检验器

C内置于Java虚拟机(及语言)的安全特性

D安全管理器及Java API

Java安全模型的前三个部分——类加载体系结构、class文件检验器、Java虚拟机(及语言)的安全特性一起达到一个共同的目的:保持Java虚拟机的实例和它正在运行的应用程序的内部完整性,使得它们不被下载的恶意代码或有漏洞的代码侵犯。相反,这个安全模型的第四个组成部分是安全管理器,它主要用于保护虚拟机的外部资源不被虚拟机内运行的恶意或有漏洞的代码侵犯。这个安全管理器是一个单独的对象,在运行的Java虚拟机中,它在对于外部资源的访问控制起中枢作用。

 

2.       类装载器体系结构

类装载器体系结构在三个方面对java的沙箱起作用:

        1):它防止恶意代码去干涉善意的代码。

        2):它守护了被信任的类库的边界。

        3):它将代码归入某类(称为保护域),该类确定了代码可以进行哪些操作。

在某个特定的类装载器试图装在一个类时,它会先默认将这个任务委派给它的双亲类装载器来装在这个类,这个双亲再依次将请求委派给它的双亲,这个委派过程一直到启动类装载器,如果启动类装载器无法装载,再依次给它的子孙装载,直到某个类装载器可以装载,再向下依次返回装载的那个类,如果都不能装载,则抛出异常。

 

 

这种委托双亲的模式好处是:启动类加载器可以抢在标准扩展类装载器之前去装载类,而标准扩展类装载器可以抢在类路径加载器之前去装载那个类,类路径装载器又可以抢在自定义类加载器之前去加载它。所以Java虚拟机先从最可信的Java核心API查找类型,这是为了防止不可靠的类扮演被信任的类,试想一下,网络上有个名叫java.lang.Integer的类,它是某个黑客为了想混进java.lang包所起的名字,实际上里面含有恶意代码,但是这种伎俩在双亲模式加载体系结构下是行不通的,因为网络类加载器在加载它的时候,它首先调用双亲类加载器,这样一直向上委托,直到启动类加载器,而启动类加载器在核心Java API里发现了这个名字的类,所以它就直接加载Java核心APIjava.lang.Integer类,然后将这个类返回,所以自始自终网络上的java.lang.Integer的类是不会被加载的。

图片来源于:http://fhz1980.blog.163.com/blog/static/35528771201010961835141/

但是如果这个移动代码不是去试图替换一个被信任的类(就是前面说的那种情况),而是想在一个被信任的包中插入一个全新的类型,情况会怎样呢?比如一个名为java.lang.Virus的类,经过双亲委托模式,最终类装载器试图从网络上下载这个类,因为网络类装载器的双亲们都没有这个类(当然没有了,因为是病毒嘛)。假设成功下载了这个类,那你肯定会想,Viruslang下的其他类痛在java.lang包下,暗示这个类是Java API的一部分,那么是不是也拥有修改Java.lang包中数据的权限呢?答案当然不是,因为要取得访问和修改java.lang包中的权限,java.lang.Virusjava.lang下其他类必须是属于同一个运行时包的,什么是运行时包?运行时包是指由同一个类装载器装载的、属于同一个包的、多个类型的集合。考虑一下,java.lang.Virusjava.lang其他类是同一个类装载器装载的吗?不是的!java.lang.Virus是由网络类装载器装载的!

 

 在有双亲委派模式的情况下,启动类装载器可以抢先在用户自定义的类装载器之前去装载类,总之,越上层的类装载器越值得信任,而越上层的类装载器越早装载类。

虚拟机不但要确定两个类型是否属于同一个包,还必须确定它们属于同一个运行时包,即它们必须是由同一个类装载器装载的。

 

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

第一趟是,检查class文件的结构是否正确。比较典型的就是,检查class文件是否以魔数OxCAFEBABE打头。

通过这趟检查,可以过滤掉大部分可能损坏的,或者压根就不是class的文件,来冒充装载。

 

第二趟是,检查它是否符合java语言特性里的编译规则。比如发现一个类的超类不是Object,就抛出异常。

 

第三趟是,检查字节码是否能被JVM安全的执行,而不会导致JVM崩溃。这里提到了一个停机的问题。内容是这样的,即不可能写出一个程序,用它来判定作为其输入而读入的某个程序,是否会停机。意思是,不可能写一个程序,让它告诉你,另外一个程序会不会中断或崩溃。

 

第四趟是,符号引用验证。一个类文件,它会包含它引用的其他类的全名和描述符,并跟他们建立符号引用(一种虚拟的,非物理连接的方式)。当程序第一次执行到需要符号引用的位置时,jvm会检查这个符号链接的正确性,然后建立真正的物理引用(直接引用)

 

4.       内置于java虚拟机(及语言)的安全特性

     1)类型安全的引用转换

     2)结构化的内存访问

     3)自动垃圾收集

     4)数组边界检查

     5)空引用检查

    虽然字节码指令集没有向用户提供不安全的、非结构化的内存访问方法,但是可以绕过字节码,即调用本地方法。当调用本地方法时,java安全沙箱完全不起作用。一旦某个线程进入一个本地方法,不管java虚拟机内置了何种安全策略,只要这个线程运行这个本地方法,安全策略将不再对这个线程适用。

    为了保证安全而内置于java虚拟机的最后一个机制,就是异常的结构化错误处理,从而使某个异常或错误导致这个错误线程的死亡,而不是使整个系统陷入瘫痪。

5.       安全管理器及java API

     安全管理器定义了沙箱的外部边界,因为它是课定制的,所以它允许为程序建立自定义的安全策略。当java API进行任何可能不安全的操作时,它都会向安全管理器请求许可,从而强制执行自定义的安全策略。要向安全管理器请求许可,java API将调用安全管理器对象的"check"方法,如checkReadcheckWirte

大家有兴趣可以看下这篇java沙箱实现的实例:

http://blog.csdn.net/flyingpig204/archive/2009/11/25/4871968.aspx

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics