java security model是Java的一个重要的架构特征,这个架构特征保证了Java可以作为网路环境程序开发的技术。因为在网络环境下的所有程序security安全是个重要因素。我们需要保证网络环境下下载的程序本地运行时安全的。
Java security model侧重于保护终端用户在运行从网络上下载的恶意程序时以免中招。实现这个目的就是通过可定制话的sandbox来实现的。一个java程序必须在这个sandbox中运行,这个sandbox可以禁止很多不安全的操作。哪些操作是不安全的或会引起潜在危害的?
Java的沙盒模式允许来自任何源的代码,但是如果代码来自未授信的来源时,沙盒就会约束这些代码做任何有害你的系统的操作和行为。Java sandbox由四大护法来保证安全性:
这四大护法中class loader和security manager提供了可定制性,从而我们可以根据我们java应用程序自身需求来定制security policy安全方针。
类加载架构(The class loader architecture )
它保证了授信类库的边界以及防止恶意代码与正常代码的交互。
为了防止恶意代码伪装成信任的代码(如写一个java.lang.MaliciousClass伪装成java.lang包下的一个类) 类加载架构机制为类提供了保护的name-space。每个加载的类的单独名字的结合构成了一个命名空间。这个name-space由JVM维护。一旦一个类被加载到一个特定的name-space,那在这个name-space中就不可以有另一个具有相同名称的类。
name-space就给加载到不同的name-space的类提供了一个防护盾;在同一个name space中的类可以直接交互;在不同的命名空间的类如果不明确告知的话甚至连对方是否存在都不清楚。我想这就是包访问的原理。
class loader的加载机制是parent delegate机制,即先有parent classloader去加载,如果找不到的话,当前class loader才去尝试加载。都加载不到就会抛class not found(ClassNotFoundException)异常。
每个自定义的class loader都会依赖于其他class loader;至少会依赖于原始的class loader.
当JVM第一次执行某个class的方法时,会要求该类的classloader去加载该方法中使用到的引用类,这个过程也是parent delegate的过程,即该类classloader会交由parent class loader去先尝试加载。
我们在写classloader时要保证那些要被自己加载的类不能声明为一个授信包的成员。
你可能已经在授信任的库中安装了一些包,这些包包含一些类;这些类你希望应用程序能够通过原始的class loader来加载,同时不希望它们被你的类加载器加载的类访问。对于这些重要的特殊类(可能包含重要资源和重要权限),我们需要在自定义的classloader中给予甄别和拦截,应该抛安全异常,也不要交由原始classloader去加载。这样的包可以称为禁止访问包(forbidden packages)。例如名为absolutePower的包是个禁止访问包,那么自定义的classloader就不应该去加载该package下的任何类如absolutePower.xxxClass,而是直接抛安全异常。
通常编写一个安全的类加载器需要使用下面四步:
Class文件检查器(The Class File Verifer)
类文件检查器检查加载的类是否是满足一个java class内部结构。如果该文件结构不合法就会抛异常。它保证了程序的健壮性。一个类文件检查器执行检验有两个阶段。第一个阶段发生在类刚被加载后,第二个阶段发生在字节码执行的时候。
阶段一:(加载后)文件本身内部检查
这一阶段只是针对文件本身做内部检查,文件结构检查,比如文件格式,文件头(0xCAFEBABE),文件是否被截断或者被加了尾巴。要保证bytecodes的一致性。语法检查,比如每个部分是否well-formed(如方法描述符应包含返回类型,参数的个数以及类型)。比如类本身是否符号java语言的一些约束条件(如类的单继承)。之后还要验证bytecodes,即字节码检查; 这个过程会涉及到一些术语,如opcodes, operands, Java Stack, frames, operand stack。这里不多讲了,感兴趣可以去研究一下。
阶段二:(执行时)符号引用的检验
符号引用检查该类引用的类文件,确保这些引用是正确的。这是将符号引用转化为直接引用的过程。当一个类被加载的过程中,它包含了对其他类的符号引用以及它们的方法和字段。符号引用只是一个字符串,包含一些名称,描述信息,如类名称,方法名称等。这是一个动态链接的过程。
Java语言的内置安全特性
JVM和Java语言内置了一些安全特性,从而加强了程序的健壮性。如
Security Manager and the Java API
通过使用类加载器可以阻止不同类加载器加载的类代码在JVM中相互干扰,但却不能保护对JVM以外的资产,如本地文件,本地进程等。这时候就需要使用Security Manager。它定义了sandbox的外边界。Java API在其执行任何可能有安全问题的操作前首先需要征求Security Manager的允许。Java API实施自定义的security policy。每个不安全的动作在security manager中都有一个方法,定义了是否在sandbox中允许执行该动作。每个方法名称都以check开头,比如说checkRead(), checkWrite()。通常要check的活动有:
以上这些操作都会有些安全风险。
当启动一个java应用时,它并没有security manager。 但是application可以在其option选项中安装一个security manager。如果没有安装security manager,那么就对java API执行任何活动时没有约束。
尽管应用程序只可以安装一个security manager,但是我们可以自己写security manager来建立多个security policy。