Axis2 WS-Security 签名和加密
通过本文,您可以获得有关公开密匙加密基本原理的介绍,然后了解 WS-Security 如何通过结合公开-私有密匙对和秘密密匙,将这些原理应用于 SOAP 消息签名和加密。Dennis Sosnoski 将继续他的 Java Web 服务 系列,本期文章讨论 WS-Security 和 WS-SecurityPolicy 签名和加密特性,并提供了使用 Axis2 和 Rampart 的示例代码。
?
安全性对于使用 Web 服务交换业务数据至关重要。如果数据被第三方截取,或者欺骗性数据被当作有效数据接收,那么会引起严重的财务或法律后果。为 Web 服务(任何形式的数据交换)设计和实现应用程序的安全处理始终是可行的,但是这种方法比较冒险,因为即使是一个小错误和疏漏都会导致严重的安全漏洞。与其他更简单的数据交换相比,SOAP 的优势之一是它支持模块化扩展。自 SOAP 首次发布以来,安全性一直是扩展的主要关注点,促使了 WS-Security 和相关技术的标准化,允许针对每一个服务相应地配置安全性。
信息交换对安全性的需求通常包含三个方面:
机密性:只有消息的目标接收者有权访问消息内容。 完整性:接收到的消息没有发生任何修改。 真实性:可以对消息的来源进行检验。WS-Security 可以让您轻松地满足这三个方面的要求。在本文中,您将理解如何通过使用 Axis2 和 Rampart WS-Security 扩展实现这点。但是,我们首先将扼要概述一下公开密匙加密的原理 — 这是 WS-Security 的加密和签名特性的主要基础。
?
要查看消息中的实际 WS-Security 信息,需要使用 TCPMon 之类的工具(见 参考资料)。首先设置 TCPMon 并在一个端口上接受来自客户机的连接,该连接随后转发给运行在另一个端口上的服务器(或另一个主机)。随后可以编辑 build.properties 文件并将 host-port 值修改为 TCPMon 的侦听端口。如果在控制台中再一次输入 ant run,应当会看到被交换的消息。清单 3 展示了一个样例客户机消息捕捉:
清单 3. 从客户机发送给服务器的第一条消息
?
SOAP 消息中的 <wsse:Security> 头部保存有所有运行时安全配置信息和签名数据。第一个项是 <wsu:Timestamp>,在 WS-SecurityPolicy 配置中被请求。时间戳包含了两个时间值:创建时间和过期时间。这两个值在本例中为 5 分钟的时间间隔,这是 Rampart 的默认设置。(可以在 Rampart 策略配置中修改这两个值)。这两个值之间的时间量稍微有些随意,但是 5 分钟是一个比较合理的值 — 足够处理客户机与服务器之间存在的适当的时钟偏移(系统时钟之间的差异),但是同时也能够限制利用消息进行重播攻击。在时间戳之后,安全头部的下一个项是 <wsse:BinarySecurityToken>。这个安全令牌是一个客户机证书,采用 base64 二进制编码形式。
安全头部中的第三个项是一个 <ds:Signature> 块,其中包含三个子元素。第一个子元素 <ds:SignedInfo> 是直接进行签名的消息部分。<ds:SignedInfo> 中的第一个子元素标识用于自身标准化和签名的算法。后面是一个 <ds:Reference> 子元素,针对签名中包含的每个消息组件。每个子 <ds:Reference> 元素根据标识符引用一个特定消息组件并提供应用到该组件的标准化和摘要算法,以及生成的摘要值。<ds:SignedInfo> 的其余子元素提供了实际的签名值和一个用于检验签名的公开密匙的引用(在本例中为此前在头部中的 <wsse:BinarySecurityToken> 中包含的证书,由 wsu:Id="CertId-2650016" 标识)。
?
仅使用加密不行吗?
如果可以提供一个仅对 Axis2 和 Rampart 使用加密的示例会很不错,但是这个功能在 Axis2 1.4(及更早版本)中被去掉了。1.5 发行版提供了一个代码补丁。如果您使用的是 Axis2 1.5 或更高版本(以及相应的 Rampart 发行版),那么可以尝试使用 encr-policy-client.xml 和 encr-policy-server.xml 策略文件来在不使用任何签名的情况下对每个消息体进行加密。
使用加密不需要 用到 清单 4 策略中的第一处修改,但这是个好主意。在使用加密时,客户机在发送初始请求时需要用到服务器证书(因为要使用证书中的服务器公开密匙进行加密)。由于客户机需要具有服务器证书,并不表示要将服务器证书发送给客户机。清单 4 策略中经过修改的 <sp:RecipientToken> 反映了这个用例,表示不应发送证书(sp:IncludeToken=".../Never"),而应当使用 thumbprint reference(实际上就是一个证书散列)。thumbprint reference 要比完整的证书更加简洁,因此使用引用可以减小消息的大小和处理开销。
实际实现加密的修改是新添的 <sp:EncryptedParts> 元素。这个元素表示将要使用加密,而内容 <sp:Body> 元素表示需要对消息中的 SOAP 消息体进行加密。
清单 4 中新添的 Rampart 配置信息包含一个 <ramp:encryptionUser> 元素和一个 <ramp:encryptionCrypto> 元素,前者为用于加密信息的公开密匙(即证书)分配一个别名,后者指出如何访问包含证书的 keystore。在示例应用程序中,对用于签名的私有密匙和用于加密的公开密匙使用了相同的 keystore,因此 <ramp:encryptionCrypto> 元素只不过是对现有的 <ramp:signatureCrypto> 元素进行重命名后的副本。
在运行时,Rampart 需要获得用于保护私有密匙的密码,这个私有密匙用于对已加密数据进行解密。前面的密码回调用于获得私有密匙密码(用于实现签名),如 清单 2 所示,还提供了用于解密的密码,因此不需要做任何修改。
为什么要导出/导入两种证书?
文本要求您为双方导出一个证书,然后将证书导入到另一方的 keystore。如果您使用了加密,那么需要为服务器证书执行这一操作,即使证书是由权威机构签名,因为加密需要访问另一方的公开密匙。另一方面,对于客户机证书,只需要将证书导入服务器 keystore,因为证书是自签名的并且无法通过其他方式验证。通过将证书导入到 keystore,您已经实现对其进行了确认,因此不需要再通过权威机构进行检验。
可以采用相同的办法处理多个使用自签名证书的客户机,只需要将每个客户机的证书导入到服务器 keystore。作为一种替代选择,与使用自签名证书不同的是,可以运行您自己的证书机构(使用 OpenSSL 之类的工具)并要求每个客户机获得由该机构签名的证书。通过这个方式,您可以向服务器 keystore 添加证书机构,并且任何具有由该机构签名的证书的客户机将被接受。或者通过支付费用来使用由权威机构签名的官方证书。
要利用新的密匙和证书,在运行客户机构建之前,必须将 client.keystore 文件复制到示例代码的 client/src 目录(或者只需将其复制到 client/bin 目录以立即生效),并在运行服务器构建之前将 server.keystore 文件复制到示例代码的 server/src 目录。
本节中的样例 keytool 命令使用了与附带的示例代码相同的文件名和密码。当您生成自己的密匙和证书时,您也可以修改这些值,但是那样做的话还需要修改示例代码以便匹配。在消息传递双方的策略文件中,keystore 密码和文件名都是 RampartConfig 中的参数。客户机密匙密码被硬编码到 com.sosnoski.ws.library.adb.PWCBHandler 类的客户机版本中,而服务器密匙密码则位于同一个类的服务器版本中。
描述名字大小下载方法本文源代码j-jws5.zip36KBHTTP
?
原文:http://www.ibm.com/developerworks/cn/java/j-jws5/