Java核心技术卷2 高级特性 学习笔记(5)

参考:Java核心技术卷2 高级特性  第九章

Java技术提供了三种确保安全的机制:

  • 语言设计特性(对数组的边界进行检查,无不受检查的类型转换,无指针算法等)。
  • 访问控制机制,用于控制代码能够执行的操作(比如文件访问,网络访问等)。
  • 代码签名,利用该特性,代码的作者就能够用标准的加密算法来认证Java代码。这样,该代码的使用者就能够准确知道谁创建了该代码,以及代码被标识后是否被修改过。

类加载器,可以在将类加载到虚拟机中的时候检查类的完整性。

为了获得最大的安全性,无论是加载类的默认机制,还是自定义的类加载器,都需要与负责控制代码运行的安全管理器类协同工作。

类加载器

Java编译器会为虚拟机转换源指令,虚拟机代码存储在以.class为扩展名的类文件,每个类文件都包含某个类或者接口的定义和实现代码。这些类文件必须由一个程序进行解释,该程序能够将虚拟机的指令集翻译成目标机器的机器语言。

类加载过程

虚拟机只加载程序执行时所需要的类文件。

虚拟机执行的步骤:

(1)虚拟机有一个用于加载类文件的极值,例如,从磁盘读取文件或者请求web上的文件,使用该机制来加载指定类文件中的内容。

(2)如果指定类拥有类型为另一个类的域,或者是拥有超类,那么这些类文件也会被加载(加载某各类所依赖的所有类的过程称为类的解析)。

(3)接着,虚拟机执行指定类中的main方法(它是静态的,无需创建类的实例)。

(4)如果main方法或者main调用的方法要用到更多的类,那么接下来就会加载这些类。

然而,类加载机制并非只使用单个的类加载器。每个Java程序至少拥有三个类加载器:引导类加载器、扩展类加载器、系统类加载器(有时也称为应用类加载器)。

引导类加载器负责加载系统类,通常从JAR文件rt.jar中进行加载。它是虚拟机不可分割的一部分,通常使用C语言来实现的。引导类加载器没有对应的ClassLoader对象。

扩展类加载器用于从jre/lib/ext目录加载“标准的扩展”。可以将JAR文件放入该目录,这样即使没有任何类路径,扩展类加载器也可以找到其中的各个类。

系统类加载器用于加载应用类。在由CLASSPATH环境变量或者-classpath命令行选项设置的类路径中的目录里或者是JAR/ZIP文件里查找这些类。

在Oracle的Java语言实现中,扩展类加载器和系统类加载器都是用Java来实现的。它们都是URLClassLoader类的实例。

类加载器的层次结构

类加载器有一种父子关系,除了引导类加载器外,每个类加载器都有一个父类加载器。根据规定,类加载器会为它的父类加载器一个机会,以便加载任何给定的类,并且只有在其父类加载器加载失败时,它才会加载给定类。

偶尔需要干涉和指定类加载器:

  • 应用代码包含一个助手方法,它要调用Class.forName(classNameString)
  • 这个方法是从一个插件类被调用的
  • classNameString执行的正式一个包含在这个插件的JAR中的类。

助手方法的类是由系统类加载器加载的,这是Class.forName所使用的类加载器。对于它来说,在插件JAR中的类是不可视的,这种现象称为类加载器倒置。要解决这个问题,助手方法需要使用恰当的类加载器,它可以要求类加载器作为其一个参数传递给它。或者,它可以要求将恰当的类加载器设置称为当前线程的上下文类加载器,这种策略在许多框架中都得到了应用。每个线程都有一个对类加载器的引用,称为上下文类加载器。主线程的上下文类加载器是系统类加载器。当新线程创建时,它的上下文类加载器会被设置称为创建该线程的上下文类加载器。因此,如果你不做任何特殊的操作,那么所有线程都会将它们的上下文类加载器设置为系统类加载器。通常,当调用不同的类加载器加载插件类的方法时,进行上下文类加载器的设置是一种好的思路。

在同一个细腻及中,可以有两个类,它们的类名和类加载器来确定的。这项技术在加载来自多处的代码时很有用。

编写自己的用于特殊目的的类加载器,这使得我们可以在向虚拟机传递字节码之前执行定制的检查。

当类加载器将新加载的Java平台类的字节码传递给虚拟机时,这些字节码首先要接受校验器的校验。校验器负责检查哪些指令无法执行的明显有破坏性的操作。除了系统类外,所有的类都要被校验。校验器执行的一些检查如下:

  • 变量要在使用之前进行初始化
  • 方法调用与对象引用类型之间要匹配
  • 访问私有数据和方法的规则没有被违反
  • 对本地变量的访问都落在运行时堆栈内
  • 运行时堆栈没有溢出

校验器总是在防范被故意篡改的文件,而不仅仅是检查编译器产生的类文件。

安全管理器与访问权限

一旦某个类被加载到虚拟机中,并由检验器检查过之后,Java平台的第二种安全机制就会启动,这个机制就是安全管理器。

安全管理器就是一个负责控制具体操作是否允许执行的类。安全管理器负责检查的操作包括以下内容:

  • 创建一个新的类加载器
  • 退出虚拟机
  • 使用反射访问另一个类的成员
  • 访问本地文件
  • 打开socket连接
  • 启动打印作业
  • 访问系统剪贴板
  • 访问AWT事件队列
  • 打开一个顶层窗口

代码来源是由一个代码位置和一个证书集指定的,代码位置指定了代码的来源。证书的目的是要由某一方来保障代码没有被篡改过。权限是指由安全管理器负责检查的任何属性。

每个类都有一个保护域,它是一个用于封装类的代码来源和权限集合的对象。当SecurityManager类需要检查某个权限时,它要查看当前位于调用堆栈上的所有方法的类,然后要获取所有类的保护域,并且询问每个保护域,其权限集合是否允许执行当前正在被检查的操作。通过检查整个调用堆栈,安全机制就能够确保一个类决不会要求另一个类代表自己去执行某个敏感的操作。

策略管理器要读取相应的策略文件,这些文件包含了将代码来源映射为权限的指令。

可以将策略文件安装在标准位置上。默认情况下,有两个位置可以安装策略文件:

  • Java平台主目录的java.policy文件
  • 用户主目录的 .java.policy文件

数字摘要

消息摘要

消息摘要是数据块的数字指纹,例如,所谓的SHA1可以将任何数据块,无论其数据多长,都压缩为160位(20字节)的序列。

消息摘要的两个基本属性:

  • 如果数据的1位或者几位改变了,那么消息摘要也将改变
  • 拥有给定消息的伪造者不能创建于原消息具有相同摘要的假消息

Java编程语言已经实现了MD5、SHA-1、SHA-256、SHA-384和SHA-512。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券