登录 |  注册 |  繁體中文


什么是XML数字签名?

分类: 其它 颜色:橙色 默认  字号: 阅读(718) | 评论(0)

什么是数字签名?

数字签名就是在信息的后面加上一段内容,可以证明信息没有被修改过。
那么怎么做到呢?
发送方对信息做一个hash计算得到一个hash值(注意,这个过程是不可逆的,也就是说无法通过hash值得出原来的信息内容)。在把信息发送出去时,把这个hash值用私钥加密后做为一个数字签名和信息一起发出去。
接收方在收到信息后,会重新计算信息的hash值,并和信息所附带的hash值(用公钥解密后)进行对比,如果一致,就说明信息的内容没有被修改过,因为这里hash计算可以保证不同的内容一定会得到不同的hash值,所以只要内容一被修改,根据信息内容计算的hash值就会变化。

什么是XML数字签名?

概要

XML Signature是一个定义数字签名的XML语法的W3C推荐标准。XML具有更好的可扩展性,为签名XML文档做了调整。XML Signature在许多Web技术中使用,如SOAP、SAML等。
XML签名为任何数据提供了完整性、消息认证、以及签名者认证服务。
XML数字签名可以应用于任何数据对象 ( 包括 XML 文档 ),也可以应用于一个或多个资源文件,或者资源文件的子集。

XML数字签名使用非对称加密,来保证数据来源和内容的正确,XML数据通过签名后,就无法被修改了。签名是由XML文档的所有或部分hash生成的摘要信息再加密而生成的,hash方式一般有md5和sha1。
因为XML文档中有不同的缩进和空格,所以需要规范化函数(canonicalizationMethod)先对文党进行处理,去除空格和其他格式,将XML数据简化为最简单的格式。为什么这很重要?因为一字之差就会生成两个不同的hash值。最后,使用签名转换来加密hash值。
这个XML电子签名使用了非对称加密和规范化函数,并且通常包含签名它的公钥。
电子签名有三种不同的形式:

  • 1.包封式签名:签名被封装在被签名的XML文档中
  • 2.签名封装被签名的XML文中
  • 3.分离式签名:被签名的XML文档和签名是分开的

XML的数字签名格式

http://www.w3.org/2000/09/xmldsig#命名空间下,XML签名包含了Signature元素。它的基本结构如下:

<Signature> 
  <SignedInfo>
    <CanonicalizationMethod/>  规范化方法,用于去除空格和其他格式
    <SignatureMethod/>
    (<Reference (URI)?>
    (<Transforms/>)?
    <DigestMethod/>  
    <DigestValue/>
    </Reference>)+
  </SignedInfo>
  <SignatureValue/>
  (<KeyInfo/>)?
  (<Object ID?/>)*
</Signature>

举例

使用签名被封装在被签名XML中的方式
需要被签名的XML文档如下:

<license>
  <test>hello world</test>
</license>

签名后的XML:

<license>
    <test>hello world</test>
    [s01]<ds:Signature
        xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        [s02]<ds:SignedInfo>
            [s03]<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2006/12/xml-c14n11"/>
            [s04]<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
            [s05]<ds:Reference URI="">
                [s06]<ds:Transforms>
                    [s07]<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                    <ds:Transform Algorithm="http://www.w3.org/2006/12/xml-c14n11"/>
                [s08]</ds:Transforms>
                [s09]<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                [s10]<ds:DigestValue>d+F/TTTxoF2Fk/knoTwHLqC7gqa+ETnTn84sNwx4c0Y=</ds:DigestValue>
            [s11]</ds:Reference>
        [s12]</ds:SignedInfo>
        [s13]<ds:SignatureValue>KdSti.....6OA==</ds:SignatureValue>
        [s14]<ds:KeyInfo>
            [s15a]<ds:KeyValue>
                [a15b]<ds:RSAKeyValue>
                    [a15c]<ds:Modulus>nM95A0J.....+GQ==</ds:Modulus>
                    [a15d]<ds:Exponent>AQAB</ds:Exponent>
                [a15e]</ds:RSAKeyValue>
            [a15f]</ds:KeyValue>
        [a16]</ds:KeyInfo>
    [a17]</ds:Signature>
</license>

元素说明

  • SignedInfo
    [s02-12]该元素的子元素包含有关所签名的内容以及签名方式的所有信息。签名算法实际上应用于该元素及其所有子元素以生成签名。
  • CanonicalizationMethod
    [s03]该元素指定了用于SignedInfo元素以便将XML规范化的规范化(C14N)算法。
  • SignatureMethod
    [s04]该元素指定了该签名的签名算法。这里的签名算法是带有RSA的SHA-256。
  • Reference
    [s05-11]这些元素指定了将要签名的数据以及在哈希运算之前应当如何对该数据进行处理。URI属性(它表示统一资源标识符)标识要签名的数据,而Transforms元素(稍后描述)指定在进行哈希运算之前如何处理数据。在该示例中,我们将使用特殊的URI——空字符串,它指定包含签名的文档是要包含在签名中的数据。XML签名标准对Reference数据使用间接签名机制。该标准不是对Reference中的所有数据进行哈希运算然后加密哈希值,而是使用由Reference的DigestMethod元素所指定的算法对每个Reference的数据进行哈希运算,然后将哈希值存储到Reference的DigestValue元素中。接下来,对SignedInfo元素和它的所有子元素(包括Reference元素)进行哈希运算;哈希值被加密以生成签名。因此,您实际上是对Reference元素中所引用数据的哈希的哈希进行签名,但是该方案仍然可以保护数据的完整性。
    **[s05]**Reference的这个可选 URI 属性标识要签名的数据对象。 在一个 Signature 中,至多可以对一个Reference省略该属性。(为了确保明确地匹配引用和对象, 要强加这个限制。)
    [s06-08]该标识与transforms一起是签名者提供的描述, 其内容有关它们如何获得已编摘形式的已签名数据对象(即,已编摘的内容)。验证者还可能以另一种方法获得已编摘的内容,只要摘要验证这种方法。
  • Transforms
    [s06-08]每个Reference元素都可以具有零个或更多个为它指定的转换。这些转换按照它们在XML中列出的顺序应用于该Reference的数据。转换使您可以在对Reference的数据进行哈希运算之前对该数据进行筛选或修改。在该示例中,我们将使用包封式签名转换,该转换选择了包含文档中除Signature元素以外的所有XML。我们必须从将被签名的数据中移除Signature元素,否则,当我们存储签名值时,可能会修改我们尝试签名的数据。
  • DigestMethod
    **[s09-10]**DigestMethod 是在应用 Transforms(如果已经指定它)之后对数据应用以产生 DigestValue 的算法。DigestValue 的签名是将资源内容与签名者密钥绑定的机制。
  • SignatureValue
    [s13]该元素包含通过签名SignedInfo元素及其所有子元素而计算得到的签名值。
  • KeyInfo
    **[s14-16]**KeyInfo表示用于验证签名的密钥。标识机制可以包括证书、密钥名称和密钥协议算法。KeyInfo是可选的有两个原因。首先,签名者可能不希望向所有文档处理方披露任何密钥信息。为什么总要告诉人家?其次,该信息在应用程序上下文中可能是已知的,并且不需要明确表示。 由于KeyInfo在SignedInfo之外,所以如果签名者希望将密钥信息与签名绑定,那么Reference可以容易地将KeyInfo作为签名的一部分标识并将其包括在内。

 

 

XML数字签名的处理过程
签名过程
XML的数字签名主要工作是根据要签名的内容创建“Signature“节点,这包含三个必要步骤,首先生成”Reference“节点,然后再这个基础上创建”SignedInfo“,最后针对”SignedInfo“生成数字签名,并最终 生成“Signature”节点,下面以“Enveloped”格式为例介绍这几个必要步骤:
 
步骤1:  生成"Reference"节点。 首先确定受保护的XML节点,可以是整个文档的根节点或者某(几)个子节点,确定完受保护的XML节点后就可以创建“Reference”根节点,如“”。
第二步需要确定受保护的节点在计算摘要前需要进行什么转换,主要是需要进行规范化处理。为什么生成摘要前要进行规范化呢?这主要是为了规范和提升跨组织和跨系统之间的互操作性。 对XML有了解的同学都知道,同样语义的XML文档可以有不同的表现方式,举个栗子: xml <Book id="001" name="Javascript core book"></Book> xml <Book name="Javascript core book" id="001"/> 上面这两个XML节点仔细观察我们可以发现他们的不同之处,前面的的节点有闭合标签,后面的节点是自闭合标签,而且两个标签的属性虽然一样,但顺序是不同的,属性之间的空白间隔也 不一样,但这两个标签在语义上是完全等价的。
 
由于XML文档的这些特点,对于语义完全一致的XML文档,经过不同XML工具的序列化和反序列化后可能是完全不同的,据此计算的摘要信息也可能是完全不同的,如果不进行规范化处理, 就给不同系统不同工具的互操作性带来一定的困难和挑战,因此在生成摘要信息前要进行规范化处理,并把使用的规范化处理算法打包到“Transforms“节点中一起发送给接收方,通常的规范化处理方法是 “http://www.w3.org/2001/10/xml-exc-c14n#”, 有兴趣的同学可以参考Exclusive XML Canonicalization, 本文不再展开介绍规范化的内容。
 
最后一步是把经过规范化处理后的XML文档内容,按照确定好的摘要算法计算摘要,常用的有MD5 (已经不安全,不建议使用), SHA1(2017年被Google证实可以发生碰撞,也不安去了),SHA3, SHA256等,然后生成“DigestMethod”和“DigestValue”子节点。
 
如果有多个节点(非根节点的情况)需要进行签名,可以重复上面的步骤为每个需要签名的节点生成一个对应的"Reference"节点。
 
步骤2:  生成“SignedInfo”节点。 Reference节点准备完毕后,就可以准备生成“SignedInfo”节点了,创建“SignedInfo”节点前,和生成摘要信息一样,需要先确定“SignedInfo”节点的规范化处理算法,和数字签名的算法,并通过 “CanonicalizationMethod”和“SignatureMethod”节点来保存:
 
 
步骤3:   生成“SignatureValue”节点。 创建“Signature”节点的最后一个必要步骤就是把第二步生成的“SignedInfo"节点,按照选定的规范化算法进行处理,并使用确定好的签名算法生成签名信息,然后保存到”SignatureValue“节点。
生成“Signature”节点, “SignedInfo"和”SignatureValue“节点准备好之后,就可以创建"Signature"节点了,这一步比较简单,只需要把”SignedInfo“和”SignatureValue“作为”Signature“的子节点就可以, 如果需要,可以把生成“SignatureValue”的签名私钥对应的公钥放到“KeyInfo”子节点,这个子节点是可选的,最终生成的“Signature”节点可以参考 [Signature例子解析]中的例子。 因为是Enveloped格式的数字签名,“Signature”节点创建完,直接作为"Reference“ URI指向的节点的子节点就可以了,  
 
 
 
签名验证过程
了解了XML的签名过程,验证签名就简单了,反过来做就行,分两步:
 
验证“SignatureValue” 收到信息的接收方,按照“SignedInfo”子节点”CanonicalizationMethod“指定的规范化算法处理整个”SignedInfo“节点,注意是整个"SignedInfo”节点,然后按照“SignatureMethod” 指定的数字签名算法验证收到的签名信息,这一步如果验证通过,可以确保整个“SignedInfo”节点的内容没有被篡改。
验证所有“Reference”, 验证完“SignatureValue”后,还需要逐一验证”SignedInfo"节点包含的“Reference",验证过程如下:
通过“Reference”节点的“URI”属性找到对应XML DOM节点(通常还需要验证这个ID在整个XML文档具有唯一性来避免XML的包装攻击)。
把找到的DOM节点按照"Reference"的”Transforms“指定的处理方法进行规范化处理。
按照“DigestMethod”指定的摘要算法对第二步规范化处理后的内容计算摘要。
把上面一步计算的摘要信息和“DigestValue”节点的摘要信息(需要进行Base64解码)进行比较,如果一致则通过,反之检验失败。
签名的验证通过这两步就可以确保传输的内容没有经过篡改,如果有人篡改了内容,则Reference的摘要验证会失败,如果篡改人重新生成篡改后的文档的摘要信息,则“SignedInfo”的签名验证会失败, 除非篡改人拥有私钥(比如私钥泄露的情况)。


上一篇:HLS的M3U8及TS介绍   下一篇:Python 教程

姓 名: *
邮 箱:
内 容: *
验证码: 点击刷新 *   

回到顶部