XML 安全: 实现安全层,第 1 部分

转载 2006年05月27日 11:17:00

基本的保密技术
级别: 初级
Manish Verma, 首席架构师, Second Foundation
2003 年 12 月 01 日

作为一种 Internet 上的信息交换格式,XML 的普及性仍然在增长——而与信息交换有关的一个重要问题是安全。没有保证信息的安全性和可靠性的机制,任何信息交换格式都是不完整的。这是 Manish Verma 的系列文章中的第一篇,讨论了在保护 XML 中发挥着至关重要作用的技术。本文主要阐述了基本的保密技术、定义了 XML 上下文中的安全性、XML 规范化以及 PKI 基础设施,并提供了逐步生成密钥的指南。第 2 部分将讨论 XML 加密和 XML 签名。这一组文章将帮助您实际掌握用于保护 XML 消息的基本技术。

对于本文的目的而言, 安全性一词涉及到,从一个客户机经过数量不定的中间机器到达最终目的地,在这一往复过程中对 XML 的保护。请注意,一个 XML 消息的不同部分可能有不同的最终目的地。保护有效载荷的不同部分,从而使预期的接收群体能够阅读它们,而同时又对其他所有中间机器保持加密状态。

保护 XML 的基本粒度单位是 元素。加密的粒度还可以进一步细化,规定加密的类型是 元素还是 内容。元素加密对整个元素(包括属性)加密,并使用 EncryptedData 元素代替它。内容加密基本上意味着只加密元素的子节点,并用 EncryptedData 元素代替。

安全意味着什么?

安全这个术语包含了以下几个方面:

  • 机密性保证只有预期的接收者阅读 XML 中预期的部分。要保证机密性,重要的是加密 XML——XML Encryption 是加密 XML 的标准。
  • 完整性保证 XML 在从源到最终目的地的传输过程中不会被改变。XML Signature 标准允许发送者在要保证完整性的内容后面附加数字签名。
  • 真实性是保证 XML 确实是由声明发送它的人发送的。随内容一起发送的 XML 签名可以帮助确保发送者的身份。有效载荷的接收者可以使用发送者的公开密钥验证数字签名。如果数字签名是有效的,身份就得到了确认,否则就不能确认。
  • 抗否认性用于保证发送者不能否认发送了 XML。由发送者的私钥生成的附在 XML 上的 XML 签名保证了发送者的不可驳性。

XML 规范化是什么?

您可以创建看起来不同但拥有相同数据或者相同语义值的 XML 文档。区别可能在于实体的结构、属性的排列、字符的编码或者不起眼的空白。因为存在这种物理差异,任何 XML 文档都不能进行字节级的等价测试。问题就在于此:数字签名依赖于字节级的等价测试,但是可能有两个逻辑上相同但包含不同字节序列的 XML 文档。

因此,如果您以数字方式签署了一些 XML标记,接下来改变了一些属性的顺序——或者增加或去掉一些不重要的空白,但没有从逻辑上改变 XML,然后再验证数字签名的时候的就会失败。要保证每次验证逻辑等价的 XML——不管物理表示如何——的数字签名都能成功,您必须保证 XML 使用公认的标准格式。这个标准称为 规范化,它是序列化 XML 的标准机制。规范化有两种形式:

  • 常规规范化:当序列化 XML 的一部分时,祖先元素的上下文和所有的名称空间声明以及 xmlns 名称空间中的属性都被包括进来。
  • 排斥性规范化:当序列化 XML 的一部分时,不包括祖先元素的上下文。

那么应该使用哪种规范化,常规规范化还是排斥性规范化呢?考虑这种情况:对于数字签名,数字签署的有效载荷可能需要从原来的消息中去掉后插入到不同的上下文中。如果使用常规规范化,载荷将包括原始消息祖先元素的上下文,以及所有的名字空间声明和 xmlns 名称空间中的属性。这样,从原始消息中提取的数字签名就不能如实地插入不同的上下文。

数字签名需要使用排斥性规范化,因为可以排除祖先元素的上下文、属性以及 xmlns 名称空间的声明,从而使数字签署的有效载荷可以移植到不同的上下文中。

实现数字签名的 API 在幕后管理规范化,数字签署 XML 时您不需要专门考虑规范化的问题。

我已经充分地讨论了规范化,以帮助您了解它的重要性以及如何适应 XML 安全基础设施的基本框架。下一个话题是 XML 安全基础设施的另一个重要部分——PKI。

PKI 基础

公共密钥基础设施(Public Key Infrastructure,简写为 PKI)使得广大公众能够使用像数字签名和 XML 加密这样的技术。数字签名和 XML 加密的核心是 密钥。密钥用于数字签署文档和验证签名,也用于加密和解密过程。PKI 受委托管理与这些密钥的创建、处理和管理有关的一切事情。

PKI 保证了以下几点:

  • 可靠而有效地管理公钥和私钥
  • 任何时候使用公钥,您都可以确信关联的私钥确实保存在您使用其公钥的对方手里

密钥是 PKI 中至关重要的部分。这一部分讨论不同类型的密钥,以及如何选择密钥的算法。

公钥-私钥组合是公共密钥基础设施的核心,建立在非对称密码的基础上。现在我讲述如何创建非对称密钥,以及如何使用它加密和数字签署 XML 数据。

在开始讨论公钥私钥以及生成它们的基本原理之前,我想首先说明加密和数字签署 XML 数据的其他方法。

在加密和数字签名中,所有的事情都最终归结为生成密钥的加密算法。以下是密钥生成算法所依据的标准:

算法类型

算法类型定义加加密算法是对称的、非对称的还是消息摘要。这是区分加密算法的根本。

  • 对称算法用于生成单个密钥,也称为共享密钥。加密和解密使用相同的密钥。发起方使用共享密钥加密或数字签署有效载荷,接下来,接收方也使用相同的共享密钥解密或者验证数字签名。传递共享密钥可能成为潜在的缺陷:共享密钥可以通过不同的方式交换,或者共享密钥本身使用其他密钥加密。这些共享密钥交换机制都难以处理。非对称密钥解决了这个问题。

    尽管对称密钥有自身的缺陷(主要是如何在互信的双方之间传递),它们最大的优点是加密解密的速度快。使用共享密钥加密消息要比使用非对称密钥加密快的多。

  • 非对称算法 用于生成成对的密钥。这是 PKI 的基础。每对密钥中有一个是公钥,另一个是私钥。私钥(或 应该)只有拥有密钥对的实体知道。消息的发送方使用接收方的公钥加密消息。预期的接收者使用相应的私钥解密消息并阅读消息。

    与对称密钥不同,公钥可以对一般公众公开,不必保密。允许公钥公开的灵活性也带来了问题,需要一种机制使普通公众能够使用它。解决的办法是 XML 密钥管理系统(XML Key Management System,简写为 XKMS),我将在以后的文章中讨论。

    非对称密钥的一个缺点是加密消息要比对称密钥花费更长的时间,而且加密时间直接与消息的长短成正比。

    使用公钥和私钥只加密共享密钥而不是整个消息可以解决加密时间长的问题。然后再使用共享密钥加密其他的消息。

  • 消息摘要是一个安全的、单向的哈希函数,把任意长度的数据转化成固定长度的校验和/哈希码。这些算法用于数字签名应用程序。要数字签署大型文件,首先使用这些算法用一种安全的方式压缩(计算固定长度的哈希码)文件,然后再用私钥签署。

密钥长度

属于上述算法类型的不同算法使用不同的密钥长度。这些长度对于不同类型的算法是足够的,如下所示:

  • 对于对称密码,128 位就足够了。
  • 不同的非对称算法对同样的位数提供的安全程度是不同的。非对称密码中最常说的 RSA 使用 2048 位密钥,相当于 128 位的对称密钥。
  • 对于消息摘要,算法的长度由算法生成的哈希码或者校验和决定。128 位大小的输出足以保证很高的机密性。使用加密算法的保密性由这样一个事实保证,即生成与哈希值匹配的明文在计算上是不可行的。

算法的质量

算法的质量指的是算法 实现的质量。这是由实现对算法规范的忠实性、算法的简洁性和加密的速度来衡量的。可以根据不同的标准进行不同的测试,以判定哪种实现更好。这是选择算法要考虑的最低的基本条件。每一类算法的个数都有限,而且新算法出现的很慢。

如何在 PKI 中使用非对称算法类型?

密钥对的工作原理如下:假定有两个实体——实体 A 和实体 B。实体 A 已经向实体 B 发送了一条加密的消息。实体 A 取得了实体 B 的公钥并用它加密消息。因此加密的消息只能使用对应的私钥解密,而私钥在实体 B 手中。这就保证了任何人都能使用接收方的公钥加密消息,但只有接收方(拥有对应的私钥的一方)能够解密。

类似地,数字签名则是消息发送方使用自己的私钥签署消息。接收方可以使用发送方的公钥验证数字签名确认消息的真实性。如果已知的发送方公钥能够验证数字签名,就认为消息是来自声明的发送方。

因此,总结一下 PKI 在 XML 加密和 XML 数字签名中的使用。

在 XML 加密中:

  1. 消息的发送方使用接受方的公钥加密消息并发送。
  2. 消息的接收方使用所拥有的相应的私钥解密消息。除了拥有对应私钥的人,其他任何人都不能解密消息,从而保证了它的机密性。

在 XML 数字签名中:

  1. 发送方使用自己的私钥数字签署要发送的消息。
  2. 接收方使用发送方的对应公钥验证数字签名。

生成公钥-私钥对

这一部分介绍生成公钥-私钥对的过程,这是加密和数字签名的基础。

步骤 1. 基本设置
您需要为 Java Cryptographic Extension (JCE) 安装并注册一个密码提供程序。JCE 提供程序必须支持生成公钥和私钥的 RSA 算法。这是因为与本文配套的示例代码(请参阅 参考资料)所使用的 XML 加密实现,只支持公私密钥对的 RSA1_5 算法类型。

在 JDK 1.4 中,SunJCE 提供程序是预先配置好的。这个 SunJCE 提供程序不适合生成非对称密钥,因为它没有包含 RSA 算法类型的实现。附带的示例代码使用了开放源代码的 JCE 提供程序 ISNetworks,它包括了对 RSA 的支持。

首先,要保证 JCE 提供程序能够使用。可以通过把提供程序的 .jar 文件放到 CLASSPATH 中实现。

其次,配置 JCE 提供程序。编辑 JAVA_HOME/lib/security 目录下的 java.security 文件,增加下面一行:


security.provider.n=com.isnetworks.provider.jce.ISNetworksProvider

Java Runtime Environment (JRE)选择 JCE 提供程序来载入 JVM。JCE 提供程序的选择是基于优先顺序的。用 n 表示替优先顺序,JRE 通过它来挑选 -- 数字越低,优先权越高。

提供程序的注册也可以通过代码动态完成。请参阅 Dynamically registering a JCE provider

如果安装了安全管理器,对于使用 JCE 的 applet 或应用程序必须授权许可。必须为每种提供程序指定许可权限。权限可以在策略文件中指定。

您可以通过在 "ext" 目录下作为一组扩展安装提供程序的 .jar 文件,更清楚地控制这种许可授权事务。

动态注册 JCE 提供程序
要动态注册 JCE Provider,可以调用 java.security.Security 类中的 addProviderinsertProviderAt 方法。 addProvider 方法在已经安装的提供程序列表后面增加新的提供程序,而 insertProviderAt 在指定的位置增加提供程序。如果安装了安全管理器,可以调用其 checkSecurityAccess 方法看看是否允动态添加新的提供程序。

步骤 2. 生成密钥对
清单 1 中的代码段说明了如何生成密钥对。

清单 1. 生成密钥对


KeyPairGenerator pairgen = null;
try {
pairgen = KeyPairGenerator.getInstance("RSA", "ISNetworks");
} catch (NoSuchAlgorithmException e) {
System.out.println("There is no such algorithm for generating the keys");
e.printStackTrace();
} catch (NoSuchProviderException e) {
System.out.println("Not a valid Provider");
e.printStackTrace();
}
SecureRandom random = new SecureRandom();
int KEYSIZE = 1024;
pairgen.initialize(KEYSIZE, random);
KeyPair keyPair = pairgen.generateKeyPair();

首先,取得一个实现了 RSA 算法的 KeyPairGenerator 对象。

KeyPairGenerator 对象提供密钥大小和一个随机数,然后调用 generateKeyPair 方法得到公私密钥对。一定要掌握好这些密钥——您将大量使用它们加密和数字签名。

生成共享密钥

您还需要一个共享密钥。在 “算法类型” 一节已经提到,共享密钥用于加密 XML 内容,而公私密钥对用于加密共享密钥,内嵌到内容中。

为了有较好的加密响应时间,而又不采用其他渠道发送共享密钥,这种戏法是必要的。使用共享密钥加密 XML 内容可以保证较好的加密响应时间,而密钥对用于加密共享密钥本身。

使用共享密钥加密非常快。共享密钥用于加密大量数据,即 XML 的真正内容。使用公司密钥加密很慢,而且直接与加密的数据大小成正比。因为共享密钥通常比内容小,公钥只用于加密共享密钥,而把共享密钥本身嵌到内容中。

本文所附示例代码中的 XML 加密实现对内容加密只能识别 Triple-DES 算法。清单 2 说明了如何使用 Triple-DES 生成共享密钥。

清单 2. 生成共享密钥


Key ky = null;
KeyGenerator kg = null;
try {
kg = KeyGenerator.getInstance("DESede", "ISNetworks");
} catch (NoSuchAlgorithmException e) {
System.out.println(
"There is no such algorithm for generating the shared secret");
e.printStackTrace();
} catch (NoSuchProviderException e) {
System.out.println("Not a valid Provider");
e.printStackTrace();
}
ky = kg.generateKey();

首先,获得一个实现了 Triple-DES 算法的 KeyGenerator 对象。

KeyGenerator 对象调用 generateKey 方法获取共享密钥。这个共享密钥用于加密 XML 内容。共享密钥本身使用上一步生成的公钥加密并嵌入 XML 内容中。

结束语

XML 在公共网络上的数据交换中发挥着卓越的作用。因此,XML 安全标准以及如何采用、解释和在不同的技术平台上实现这些标准受到了更多的关注。本文中,我客观地定义了安全性及其基本技术,即 XML 规范化和 PKI 基础设施,在实现 XML 的安全交换中发挥着重要的作用。在这个基础上更进一步,本系列的下一篇文章中我将讨论 XML 加密和 XML 数字签名,并提供使用它们的详细指南。

参考资料

关于作者

Manish Verma 是 Second Foundation 的首席架构师,这是一家全球性的 IT 服务企业。Manish 在软件开发生命期的方方面面有 10 年的经验,曾经设计过使用全然不同的系统的客户组织的集成策略。Manish 在集成方面的专长建立在理解各种技术的基础上,包括各种不同的遗留系统、.NET、Java 技术和最新的中间件技术。在进入 Second Foundation 之前,Manish 先后在 Quark Inc.、Hewlett Packard、Endura Software 和 The Williams Company 做过软件架构师和技术主管。您可以通过 mverma@secf.com 与 Manish 联系。

 

相关文章推荐

Web services 安全实践,第 1 部分: 基于 HTTP Basic Authentication 为 Web services 配置传输层安全机制

转自:http://www.ibm.com/developerworks/cn/webservices/1106_webservicessecurity/index.html。     ...

C#——安全护卫设计和部分实现

其实这个是很久以前改的一个软件了,修改了大量的fooying的代码,3q fooying,他的个人博客点击打开链接 简单备注:该软件使用C#写成,内容见下图集,其中大部分功能都已经能够很好的执行,但...

第一部分 线程安全(1)——变量安全

线程安全线程安全包含两个方面变量安全:进程中有多个线程在同时运行,而这些线程可能会同时运行某一段代码如果每次运行结果和单线程运行的结果是一样的。而且其他变量的值也和预期的是一样的,称为变量安全。反正,...
  • cuiran
  • cuiran
  • 2011-01-18 17:41
  • 3147

VC++信息安全编程(1)分析实现程序自我复制

程序自我复制,是软件程序备份的一种功能,防止程序被修改,被调试,被破解。详细代码分析如下#ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE sta...

VisualC++信息安全编程(1)内联汇编实现NT下读MBR

MBR,全称为Master Boot Record,即硬盘的主引导记录。  为了便于理解,一般将MBR分为广义和狭义两种:广义的MBR包含整个扇区(引导程序、分区表及分隔标识),也就是上面所说的主引导...

一个线程安全的计数器实现(java),可以让一个变量每天从1开始递增

前几天工作中一段业务代码需要一个变量每天从1开始递增。为此自己简单的封装了一个线程安全的计数器,可以让一个变量每天从1开始递增。当然了,如果项目在运行中发生重启,即便日期还是当天,还是会从1开始重新计...
  • nmgrd
  • nmgrd
  • 2017-08-09 20:10
  • 461
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)