java是一种类型安全的语言,它有四类称为安全沙箱机制的安全机制来保证语言的安全性,这四类安全沙箱分别是:
- 类加载体系
- .class文件检验器
- 内置于Java虚拟机(及语言)的安全特性
- 安全管理器及Java API
本篇博客主要介绍“内置于Java虚拟机(及语言)的安全特性”的基本原理;如需了解其它几类安全机制可以通过上面的博客链接进入查看。
简介jvm装载一个类,并且对字节码进行了四趟扫描,这些字节码就能安全地被执行了。然而去了这些安全校验,jvm在执行字节码时还进行了一些内置的安全机制校验。这些安全机制主要包括:
- 内存自动分配
- 自动拉机回收机制
- 数组边界检查
- 空指针检查
- 异常处理机制
在编写java程序时几乎不能直接分配内存,比如当new一个对象时,jvm会在堆中自动帮程序分配好内存,当在方法中申明一个引用或常量时,jvm则会在栈上自动分配好内存;不能直接分配内存能够控制程序不小心或者恶意地覆盖一些重要地内存数据。注意,前面说“几乎不能”是因为可以通过反射调用sun.misc.Unsafe的方法是可以操作指定位置的内存(当然也是有限制的);还有一种方法可以破坏内存自动分配,那就是调用jni,对于本地方法,java安全机制完全不起作用,当一个线程执行本地方法时,它就跳出了java的安全沙箱;jni是为了扩展性而牺牲了一些安全性。
自动垃圾回收机制自动垃圾回收机制是java的一个重要特性,它的主要作用是为了防止内存泄漏,也是一种安全机制。一些没有自动垃圾回收的语言比如C++经常出现的问题是忘了调用对象的析构函数而造成内存泄漏。然而java的自动垃圾回收机制并不代表程序员不用关心内存泄漏问题了,因为内存的自动垃圾回收是需要特定条件的(无引用);自动垃圾回收机制是一个很长的话题,想要详细了解的话推荐参考《Java性能优化权威指南》的第三章。
数组边界检查数组边界检查也是一种控制内存访问的安全机制,对于其它没有数组边界检查的语言比如C语言,很常见的一种攻击手法是“缓冲区溢出攻击”,比如程序中定义了个长度为16的数组,如果没有数组边界异常,有漏洞或者恶意的程序可能会读取或操作下标为100的内存,而该内存如果存储了重要数据,就可能被读取或者被篡改,从而引发安全问题。
空指针检查空指针检查是为了防止程序出现不可预期的结果,调用空对象的方法或者字段时会抛出java.lang.NullPointerException,这是一种非受查异常。假如程序出现空指针使用的情况,很大的可能是因为程序员的粗心导致的,如果不通过抛出异常中断程序,可能会导致不可预期的结果,比如程序员以为执行了某个对象的某个方法,但是因为使用了空对象却没有执行。
异常处理机制最后一种安全机制就是java的异常处理,java的异常处理是基于线程的,而不是基于进程的,这样就保证了异常处理是轻量级的,如果一个线程出现了异常,java会沿着该线程的方法调用栈一直往上层抛异常,直到异常被处理,如果每层方法栈都没有处理该异常的话就会终止该线程,而此时如果还存在非守护线程的话就不会终止jvm进程;这样就不会影响其它正确执行的线程了。