技术 · 阅读记录
【译】Java安全概述
注意 - 这篇文章是在Java1.5基础上书写的。
一、介绍
Java平台在安全上进行着重的设计。Java本身是类型安全的,它还提供了自动垃圾收集,用于增强应用代码的稳健性。一个安全的类(class)加载和认证机制确保仅有合法的Java代码可以被执行。
最初的Java平台版本创建了一个安全的环境用于执行潜在不可信的代码,例如在公共网络下载的Java applet。伴随着平台升级以及广泛的部署,Java安全架构也相应的进化用于支持正在扩展的服务集合。现在,这个架构包含了一个巨大的集合。集合中包含应用程序接口(APIs),工具;还包含通用安全算法、机制和协议的实现。这个安全架构提供给开发者一个综合的安全框架用于开发应用程序,它还提供给用户或管理员一套可以安全管理应用的工具。
Java安全APIs横跨广泛的应用区域。加密和公钥基础设施(PKI)的接口为开发安全应用提供了潜在的基础。执行认证和访问控制的接口使应用程序可以防范受保护资源的未授权访问。
这些APIs允许多个可操作的算法和其它安全服务的实现。服务使用providers实现。providers通过标准接口嵌入到Java平台中。这些标准接口可以使应用程序容易地获取安全服务,而无需关心他们具体的实现。这些APIs允许开发者如何整合安全到他们的应用中,而不是如何实现复杂的安全机制。
Java平台包含了一些供应商(provider),这些供应商实现了安全服务的基础版。平台也允许安装额外的定制供应商。这可以使开发者在平台上扩展新的安全机制。
这篇文章是Java平台安全的概述。其内容从语言安全特性到安全APIs、工具以及一些内置的组件。这些组件包含服务、显著的关键包和类。
二、Java的语言安全和字节码验证
Java语言被设计为类型安全和容易使用。它提供了自动内存管理、垃圾收集、以及数组的范围检查。这些措施降低了开发者的整体编程负担,从而促使更少的编程错误更安全、更健壮的代码。
此外,Java语言定义了不同的访问修饰符。这些修饰符可以用来修饰Java类、方法、以及成员变量。这使开发人员能够限制他们的类实现适当的访问。具体来说,语言定义了四个不同的访问级别:private,protected, public,如果未指定,package。最开放的访问修饰符是 public,允许任何人访问。最限制性修饰语是private,私有成员(一个方法或者成员变量)不允许类外访问。protected修饰符允许任何子类,或者同一个包内的其它类访问。包级别访问只允许同一包内的类访问。
编译器将Java程序翻译为一种独立于机器的字节码表示。被调用字节码验证器去确保只有合法的字节码才能在Java运行时中执行。它依照Java语言规范检查字节码,确保没违反Java语言规则或命名空间的限制。验证器也检查内存管理违规,栈下溢或溢出和非法数据类型转换。一旦字节码验证,Java运行时准备执行。
三、基础安全架构
Java平台定义了一个APIs集合。该集合包含主要的安全区域,其中又加密、PKI、认证、安全通信和访问控制。这些APIs允许开发者很容易把安全整合到应用代码种。这些APIs依据如下原则设计:
1、实现的独立性
应用无需实现安全组件。这些应用只需请求Java平台的安全服务即可。Providers实现这些安全服务。他们通过标准接口嵌入到Java平台中。为了安全功能,一个应用也许会依赖多个独立的providers。
2、实现的互用性
在应用之间,Providers具有互用性。特别地,一个应用不会绑定到一个特定的Provider,一个Provider也不会绑定到一个特定的应用。
3、可扩展的算法 Java平台包含一些内置的Provider。这些Porvider实现了安全服务 基础内容。在今天,这些安全服务被广泛使用。但是,一些应用也许依赖新兴的标准,而不是依据被实现的。Java平台支持为实现这些服务而定制的Provider去安装。
3.1 安全Provider
在Java平台中,java.security.Provider类封装了安全Provider的概念。它指明Provider的名字,并列出被实现的安全服务。也许许多Provider被同时配置,并按特定偏好顺序被列出。当安全服务被请求,实现服务的高优先级的Provider被选择。
应用依赖相关的getInstance方法来获取来自潜在Provider的安全服务。举个例子,信息摘要的创建可以描述为Provider提供的一种类型的服务。(第四章讨论信息摘要和其它密码服务。)一个应用调用java.security.MessageDigest类的getInstance方法去获取一种特定的信息摘要算法的实现,例如MD5。
1
MessageDigest md = MessageDigest.getInstance("MD5");
程序也许可以通过指定Provider名字来指定选择一种特定Provider的实现。
1
MessageDigest md = MessageDigest.getInstance("MD5", "ProviderC");
图1和图2阐明请求一个MD5信息摘要的实现设置。两幅图均显式了三个实现信息摘要算法的Provider。三个Providr从左到右(1到3)按偏好进行排序。在图1中,应用没有指定Provider名字进行请求一个MD5算法实现。这些Provider按照优先序列继续搜索,第一个实现该算法的Provider,ProviderB,被返回。在图2中,应用请求一个被ProviderC实现的MD5算法实现。这时,虽然有较高优先序列的ProviderB也提供一个MD5实现,但是ProviderC也会被返回。

Sun公司实现的Java平台中包含很多预先配置的默认Provider。这些Provider提供了可以被应用使用的安全服务的基础集合。注意,其它Java平台供应商也许会包含不同的,封装特定安全服务集合的Provider集合。本文提及的默认内置的Provider,其均是指Sun公司实现的。
以下章节里包含在不同安全区域(加密、认证等)的相关安全服务的描述。这些服务被默认的Provider提供。附录C表中简要说明了所有的默认Provider。
3.2 文件位置
Java安全的某一方面可以使用设置安全属性来定制。这些方面在本文中被提及过,包含配置Provider。也许你静态的在安全属性文件中配置安全属性。安全属性文件默认是在被安装的Java运行环境(JRE)目录的 lib/security 目录下的 java.security 文件。安全属性可以通过调用java.security.Security类的适当方法来动态配置。
本文中提及的工具和命令均在~jre/bin目录下。~jre表示JRE的安装目录。第五章提及的cacert文件在~jre/lib/security目录下。
四、加密
Java加密架构是一个在Java平台中为了访问和开发加密功能的框架。它包括用于各种加密服务的API。这些加密服务包括:
- 信息摘要算法
- 数字签名算法
- 对称块加密
- 对称流加密
- 非对称加密
- 基于密码的加密(PBE,Password-based encryption)
- 椭圆曲线密码体制(ECC)
- 密钥协商算法
- 密钥生成器
- 消息认证码(MACs)
- (伪)随机数发生器
出于历史的出口管制原因,加密API被组织为两个不同的包。java.security包中的类(例如Signature和MessageDigest)不受出口管制控制。而javax.crypto包中的类(例如Cipher和KeyAgreement)受出口管制控制。
加密接口是基于Provider的,允许多个和互操作的加密实现。有些Provider在软件级别实现加密操作,而有些在硬件令牌中(例如,在智能卡设备上或在硬件加密加速器上)实现那些操作。Provider实现受出口管制的服务必须进行数字签名。
Java平台中包含很多内置的Provider,它们实现了很多常用的加密算法,例如RSA,DSA和ECDSA签名算法;DES,AES和ARCFOUR加密算法;MD5和SHA-1信息摘要算法;以及Diffie-Hellman密钥协商算法。那些默认的Provider在Java代码中实现加密算法。
Java平台还包括一个内置的提供者,它充当一个本地PKCS#11(v2.x)令牌的桥接器。这个叫做SunPKCS11的Provider允许Java应用无缝地访问位于可兼容PKCS11的令牌上的密码服务
五、公钥基础设施(PKI)
公钥基础设施(PKI)是一个用于支持基于公钥加密的信息安全交换的框架术语。它允许(人员、组织等的)身份被绑定到数字证书,并提供一种验证证书的真实性的方法。PKI包含密钥、证书、公钥加密,以及生成和数字签署证书的受信任的认证机构(CAs)。Java平台包含了对X.509数字证书和证书撤销列表(CRLs)支持的API和Provider,其也支持兼容PKIX的认证路径构建和验证。和PKI相关的类位于java.security和java.security.cert包中。
5.1 密钥和证书存储
Java平台通过密钥和证书存储提供了对密钥和证书的长期持久存储。具体来说,java.security.KeyStore类代表一个密钥库(key store),它是一个加密密钥或者(和)可信任证书(例如,在认证路径验证期间使用)的安全存储库;java.security.cert.CertStore类代表一个证书存储区(certificate store),它是一个公共的、潜在的巨大的存储库,该存储库用于存储不相关且通常不受信任的证书。CertStore也存储CRLs。
用类型来区分KeyStore和CertStore的实现。Java平台包括标准的PKCS11和PKCS12密钥存储类型,这些类型实现必须与RSA安全性的PKCS规范兼容。它还包含一个专有的基于文件的被称为JKS(Java Key Store)的密钥存储类型,称为JKS(它代表“Java密钥存储”),以及一个称为DKS(Domain Key Store)的类型,该类型是作为单个逻辑密钥库的密钥库集合。
Java平台包含了一个特殊的内置JKS密钥存储库(也就是cacerts文件),它包含了一些著名的、受信任的CA的证书。keytool实用工具可以列出在cacerts中包含的证书(参见第10章中的安全特性文档链接)。
在第三章节中提及的SunPKCRL11 Provider包含一个PKCS11 KeyStore实现。这意味着通过KeyStore的API可以访问和使用存储在安全硬件(例如智能卡)中的密钥和证书。请注意,智能卡密钥不被允许离开设备。在这种情况下,KeyStore的API返回的java.security.Key对象应用也许仅仅是一个简单的密钥引用,该引用也许不包含实际的密钥材料。这样的Key对象只能被用来在密钥存储设备上执行加密操作。
Java平台还包含一个LDAP证书存储类型,该类型用来访问存储在LDAP目录下的证书;以及一个内存收集证书存储类型,该类型用来访问使用java.util.Collection对象进行管理的证书。
5.2 PKI工具
有两种内置的工具用于处理密钥、证书和密钥存储:
keytool被用来创建和管理密钥存储。它能
- 创建公钥/私钥对
- 显示、导入、导出被存储为文件的X.509 v1、v2和v3版本的证书
- 创建自签名证书
- 向CAs的颁发证书(PKCS#10)请求
- 基于证书请求创建证书
- 导入从证书请求发向的CAs获取到的证书回复
- 将公钥证书指定为可信任的
- 接受密码并将其安全地存储为密钥
jarsigner工具被用来签署JAR(Java ARchive)文件或者去验证被签名的JAR文件的签名。JAR文件格式允许将多个文件绑定到一个单独的文件中。通常,JAR文件包含与applet或应用相关联的类文件和辅助资源文件。jarsigner工具被用来签署JAR(Java ARchive)文件或者去验证被签名的JAR文件的签名。JAR文件格式允许将多个文件绑定到一个单独的文件中。通常,JAR文件包含与applet或应用相关联的类文件和辅助资源文件。当你想对代码进行数字签名,首先,你需要使用keytool生成或者导入合适的密钥和证书到你的密钥库中(如果那里没有的话),然后使用jar工具把代码放入到一个JAR文件中,最后使用jarsigner工具去签署这个JAR文件。jarsigner工具可以访问访问一个密钥库去查找任意的被需要去签署JAR文件的密钥和证书,或者去验证被签署的JAR的签名。
注意 - jarsigner可以有选择地生成一个包含时间戳的签名。验证JAR签名的系统(例如Java插件)可以检查时间戳,并且接受一个已签名的JAR文件。在这里,用于签名的证书是一个有效的,而不是一个当前需要的的证书。(证书通常每年都会过期,而期望JAR文件创建者每年重新部署已部署的JAR文件是不合理的。) —-
六、认证
认证是确定用户身份的过程。在Java运行时环境中,它是识别执行Java程序的用户的过程。在某些情况下,这个过程可能依赖于“加密”一章中描述的服务(第4章)。
Java平台提供了允许应用程序通过可插入的登录模块执行用户身份验证的API。应用程序调用javax.security.auth.login包中的LoginContext类,该类依次引用一个配置。该配置指定哪个实现javax.security.auth.spi.LoginModule接口的登录模块去执行实际的认证。
由于应用程序只与标准的LoginContextAPI进行通信,所以它们可以独立于底层的插件模块。新的或更新的模块可以插入到应用程序中,而无需修改应用程序本身。图3说明了应用程序和底层登录模块之间的独立性。
需要注意的是,尽管登录模块是配置在Java平台中的可插入的组件,但它们并不是通过安全Provider插入的。因此,它们不遵循第三章中描述的Provider搜索模型。相反,登录模块是由它们自己的独特配置管理的,如上图所示。
Java平台提供了以下内置的登录模块,它们都在com.sun.security.auth.module包中:
Krb5LoginModule为了使用Kerberos协议认证。JndiLoginModule为了使用LDAP或者NIS数据库进行用户名密码认证。JndiLoginModule为了用于登录任何类型的密钥存储库,包括PKCS#11环密钥库。
在在两个对等点之间建立安全通信通道的过程中也可以实现身份验证。Java平台提供了许多标准通信协议的实现,下面一节将讨论这些协议。
七、安全通信
通过网络传输的数据可以由非预期接收方访问。当数据包括密码和信用卡号码等隐私信息时,必须采取措施保证未经授权的当事人难以理解该数据。确保数据发送到合适的接收方,并且保证在传输过程中数据不会被有意或者无意的修改,也是同样重要的。