一 介绍
自从Java技术出现以来,关于Java平台本身的安全问题以及Java技术实施过程中引起的新的安全问题引起了大家强烈而持续增长的关注。从一个技术提供者的角度来看,Java安全包括了两个方面:
- 提供一个安全的、准备好的Java平台,在该平台上可以以一种安全的方式来运行Java程序。
- 提供可在Java编程语言中使用的安全工具和服务,这些工具和服务可以支撑更大范围的对安全敏感的应用,例如在企业级应用领域。
1.1 原始的沙盒模型
Java平台一开始提供的安全模型作为沙盒模型(sandbox model)而广为人知,该模型旨在提供一个对于从网络上获取的非信任代码的非常严格的校验环境。sandbox模型的实质就是:本地代码是被信任的,对于系统资源(例如文件系统)有所有的访问权限;同时下载的远程代码(applet)是不被信任的,只能访问沙盒内部允许的有限资源。沙盒模型如下图所示:整体安全性通过一系列机制来强制实施。首先,Java语言被设计成类型安全并易于使用的。期望的效果是程序员的负担变小以至于他们犯难以察觉错误的概率相较于使用其他编程语言例如C或C++会降低。像内存管理、垃圾回收、字符串和数组越界检查等安全特性就是Java语言帮助程序员编写安全代码的典型例子。
其次,编译器和字节码校验器确保只有合法的Java字节码会被执行。字节码校验器,伙同Java虚拟机,保证了运行时的语言安全性。
此外,一个classLoader定义了一个局部命名空间,可用来确保不被信任的代码不能干扰到其他程序的运行。
最后,对于系统的关键资源的访问,由Java虚拟机来做居间调节,由SecurityManager做进一步的检查,SecurityManager将一段不被信任的代码的行为限制到最少。
JDK1.1引进了“签名程序”的概念,像下图展示的一样。在这个版本下,如果代码片段的签名密钥被收到它的终端系统识别为可信任,那么该签名的代码就会和本地代码一样受信任。签名代码,连同它们的签名,使用JAR格式被传递。在JDK1.1,未签名的远程代码(applet)仍然在沙盒中运行。
1.2 沙盒模型的进化
新的Java SE平台安全体系,如下图所示,因为下面列出的目的而被引入。- 粒度划分良好的访问控制
然而,这样的编程对安全非常敏感并且要求有高超的技巧和对计算机安全有深入的理解。新的安全体系会使其变得更简单和更安全。
- 可轻松配置的安全策略
- 易于扩展的访问控制体系
- 将安全检查扩展到所有的Java程序,不只是applets
最终,一个隐含的原因是对安全相关类(包括SecurityManager和ClassLoader类)进行内部的调整修改,以此来减少在未来编程中造成不易察觉的安全漏洞的风险。
二 新保护机制 -- 基本概念概览
我们现在在一些细节上重温一下新的保护体系,并对其功能进行一个简要说明。我们从新体系背后的基本概念概览开始。然后以一个自然的顺序介绍主要的新增类,从许可(permission)描述开始,然后继续到规则(policy)及其相关特征,跟着是访问控制(access control)和它的用处,最后涵盖类解析和加载中的安全。一个基本概念和系统安全的重要组成部分就是保护域(protection domain)。一个域可以由一个当事人身份(principal)可直接访问的一组对象来界定,当事人身份(principal)就是在计算机系统中许可(以及由此产生的责任)被赋予或绑定的实体。JDK1.0使用的沙盒就是一个有固定边界的保护域的例子。
保护域概念为各保护单元的聚合和隔离提供了一个方便的机制。 例如,可以实现(但尚未作为一个内置的特性提供)将相互交互的保护域分开,这样一来任何被许可的交互都必须要么通过被信任的系统代码完成要么被相关保护域明确的允许。注意到已存在的对象访问规则在新安全体系下仍然有效。
保护域主要分为两种不同的类型:系统域和应用程序域。重要的是所有的受保护的外部资源只能通过系统域访问,这些资源包括文件系统、网络、屏幕和键盘等。下图展示了Java应用程序环境中保护域的结构。
反过来讲,当一个系统域调用一个应用程序域的方法时,例如当AWT系统域调用一个applet的paint方法来展示该applet,在任何时候保持实际起作用的访问许可和应用程序域激活的当前许可相同,都是至关重要的事情。
换句话说,一个不怎么“强大”的域不能通过调用较“强大”的域或者被较“强大”的域调用来获得额外的许可。
这里关于一个线程涉及到两个保护域情况的讨论自然可以适用到一个线程跨越多个保护域的情况。一个简单又聪明的计算许可的指导规则如下:
- 一个执行线程的许可集合被认为是该执行线程所跨越的所有保护域的许可集合的交集。
- 当一段代码调用了doPrivilege方法(看下面),如果该行为被这段代码的保护域许可,并被其直接或间接调用或进入的所有保护域所许可的话,执行线程的许可集合被认为是直接包含了一个许可。
在执行过程中,当要访问一个关键的系统资源(如文件I/O和网络I/O)时,资源处理代码直接或间接的调用一个特殊的AccessController类方法,该方法评估资源访问请求并决定是允许还是拒绝。
该评估遵循并推广上面给出的“指导规则”。但评估实施的具体步骤在各实现中可能会有不同。基本的方针是检查调用历史及其对应的保护域赋予的许可,如果最终请求被许可,则默默返回;如果最终被拒绝,则抛出一个安全异常。
最后,每一个域(系统的或是应用程序的)可能还需要对自己的域边界范围内的资源实现额外的保护。例如,一个银行系统可能需要支持并保护像账户检查、储蓄和提现等这些内部概念。由于这种保护的语义不太可能被Java2 SDK提前描述或者强制规范,因此在这个层次上的保护系统最好是由系统或应用的开发者来实现。然而,无论何时只要合适,我们都会提供原生的功能来简化开发者的工作。一个这种原生功能就是签名对象类,我们将在后面描述其细节。
===========================================================================
本技术文档的翻译工作由不动明王1984独自完成,特此声明。
翻译辛苦,珍惜劳动,引用时请注明出处!
===========================================================================
下一篇:Java Security Architecture--Java安全体系技术文档翻译(二)