沙箱安全机制
Java安全模型的核心就是Java沙箱(sandbox)。
沙箱是一个限制程序运行的环境。沙箱机制就是将 Java 代码限定在虚拟机(JVM)特定的运行范围中,并且严格限制代码对本地系统资源访问,通过这样的措施来保证对代码的有效隔离,防止对本地系统造成破坏。沙箱主要限制系统资源访问,那系统资源包括什么?——CPU、内存、文件系统、网络。不同级别的沙箱对这些资源访问的限制也可以不一样。
所有的Java程序运行都可以指定沙箱,可以定制安全策略。
在Java中将执行程序分成本地代码和远程代码两种,本地代码默认视为可信任的,而远程代码则被看作是不受信的。对于授信的本地代码,可以访问一切本地资源。而对于非授信的远程代码在早期的Java实现中,安全依赖于沙箱 (Sandbox) 机制。如下图所示 JDK1.0安全模型
但如此严格的安全机制也给程序的功能扩展带来障碍,比如当用户希望远程代码访问本地系统的文件时候,就无法实现。因此在后续的 Java1.1 版本中,针对安全机制做了改进,增加了安全策略,允许用户指定代码对本地资源的访问权限。如下图所示 JDK1.1安全模型
在 Java1.2 版本中,再次改进了安全机制,增加了代码签名。不论本地代码或是远程代码,都会按照用户的安全策略设定,由类加载器加载到虚拟机中权限不同的运行空间,来实现差异化的代码执行权限控制。如下图所示 JDK1.2安全模型
当前最新的安全机制实现,则引入了域 (Domain) 的概念。虚拟机会把所有代码加载到不同的系统域和应用域,系统域部分专门负责与关键资源进行交互,而各个应用域部分则通过系统域的部分代理来对各种需要的资源进行访问。虚拟机中不同的受保护域 (Protected Domain),对应不一样的权限 (Permission)。存在于不同域中的类文件就具有了当前域的全部权限,如下图所示 最新的安全模型(jdk 1.6)
组成沙箱的基本组件:
- 字节码校验器(bytecode
verifier):确保Java类文件遵循Java语言规范。这样可以帮助Java程序实现内存保护。但并不是所有的类文件都会经过字节码校验,比如核心类。 - 类装载器(class loader):其中类装载器在3个方面对Java沙箱起作用
它防止恶意代码去干涉善意的代码;
它守护了被信任的类库边界;
它将代码归入保护域,确定了代码可以进行哪些操作。
虚拟机为不同的类加载器载入的类提供不同的命名空间,命名空间由一系列唯一的名称组成,每一个被装载的类将有一个名字,这个命名空间是由Java虚拟机为每一个类装载器维护的,它们互相之间甚至不可见。
类装载器采用的机制是双亲委派模式。
- 从最内层JVM自带类加载器开始加载,外层恶意同名类得不到加载从而无法使用;
- 由于严格通过包来区分了访问域,外层恶意的类通过内置代码也无法获得权限访问到内层类,破坏代码就自然无法生效。
存取控制器(access controller):存取控制器可以控制核心API对操作系统的存取权限,而这个控制的策略设定,可以由用户指定。
安全管理器(security manager):是核心API和操作系统之间的主要接口。实现权限控制,比存取控制器优先级高。
安全软件包(security package):java.security下的类和扩展包下的类,允许用户为自己的应用增加新的安全特性,包括:安全提供者;消息摘要;数字签名(keytools https);加密;鉴别
Native
package com.newer;
public class Demo1 {
public static void main(String[] args) {
new Thread(() -> {
},"my thread name").start();
}
// native:凡是带了native关键字的,说明java的作用范围达不到了,会去调用底层C语言的库
// 会进入本地方法栈
// 调用本地方法本地接口 JNI
// JNI作用:扩展Java的使用,融合不同的编程语言为Java所用!
// Java诞生时,C,C++横行,想要立足,必须要有调用C,C++的程序
// 在内存区域中专门开辟了一块标记区域:Native Method Stack,登记native方法
// 在最终执行时,加载本地方法库中的方法通过JNI
// Java程序驱动打印机,管理系统。在企业级应用中较为少见!
private native void start0();
// 调用其他接口:Socket,WebService,http
}
凡是带了native关键字的,说明java的作用范围达不到,去调用底层C语言的库
JNI:Java Native Interface(Java 本地方法接口)
凡是带了native关键字的方法就会进入本地方法栈,其他的就是Java栈
本地方法栈(Native Method Stack)
它的具体做法是Native Method Stack中登记native方法,在(Execution Engine)执行引擎执行时,加载Native Libraies(本地库)。
PC寄存器
每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向下一条指令的地址,也即将要执行的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不记。
方法区(Method Area)
方法区是被所有线程共享。所有字段和方法字节码,以及一些特殊方法(构造方法,接口代码)也在此定义。简单来说,所有定义的方法的信息都保存在该区域。这个区域属于共享区间。
当类加载器加载完成类之后,会将类信息、运行时常量池、静态变量(此处指的是指针,如果是一个对象对象的分配还是在堆中)等存储在方法区;但在JDK不同版本对字符串常量和静态变量的存储有所不同。
静态变量,常量,类信息(构造方法,接口定义),运行的常量池存在方法区中,但是实例变量存在堆内存中,与方法区无关
方法区存在static,final,Class,常量池等