ONVIF专题--WS-Security

1 概述

本文档中使用了下列名称空间:

前缀

名称空间

 

s

http://www.w3.org/2001/12/soap-envelope

soap根nm,定义soap中最基本Envelope、Header、Body、Fault等数据结构

ds

http://www.w3.org/2000/09/xmldsig#

xml签名根nm,定义xml签名的数据结构,

标准:[https://www.w3.org/TR/2002/REC-xmldsig-core-20020212/Overview.html ]

xenc

http://www.w3.org/2001/04/xmlenc#

xml加密根nm,

标准:[https://www.w3.org/2008/xmlsec/Drafts/xmlenc-core-11/]

m

http://schemas.xmlsoap.org/rp

从xsd文件来看,像是描述数据from和to的标准,版权属于微软

wsse

http://schemas.xmlsoap.org/ws/2002/04/secext

WS-Security的根nm(也是缩写)

2 报文保护

2.1 数字签名 和 安全证书:

基于公私钥的数据加密技术,主要目的是防止数据传输过程中被冒充、被篡改、被非法截获

是站在数据发送方的角度,保护数据

2.2 安全性令牌(token)

用户调用服务器API,向服务器发送的一个可靠的验证信息,用于服务器判断是否为用户

所以技术的目的在于服务器认证请求发起者,减少传统web请求场景下网络上多次密码交互引入的风险

3 安全性元素

3.1. UsernameToken 元素

在soap的报文头中包含安全令性令牌,定义如下,令牌包含用户名节点和可选密码节点(wsse标准建议只有在使用安全的传输时才传送该元素)

疑问:为什么UsernameToken需要Id属性?

安全性令牌是服务端用来标记用户的技术,wsse标准并没有限制一个Username与Password的唯一对应关系,理论上是可以(甚至鼓励)实现一个Username对应多种Password方式的。因此Username某些情况下不足以唯一标记一个安全性令牌,因此需要增加Id属性,目的是唯一标记一个UsernameToken,另外从Id属性的类型xsd:ID也能反应设置这个属性的目的。

<xsd:element name="UsernameToken">

    <xsd:complexType>

        <xsd:sequence>

            <xsd:element ref="Username" />

            <xsd:element ref="Password" minOccurs="0" />

        </xsd:sequence>

        <xsd:attribute name="Id" type="xsd:ID" />

        <xsd:anyAttribute namespace="##other" />

    </xsd:complexType>

</xsd:element>

<xsd:element name="Username">

    <xsd:complexType>

        <xsd:simpleContent>

            <xsd:extension base="xsd:string">

                <xsd:anyAttribute namespace="##other" />

            </xsd:extension>

        </xsd:simpleContent>

    </xsd:complexType>

</xsd:element>

<xsd:element name="Password">

    <xsd:complexType>

        <xsd:simpleContent>

            <xsd:extension base="xsd:string">

                <xsd:attribute name="Type" type="xsd:QName" />

                <xsd:anyAttribute namespace="##other" />

            </xsd:extension>

        </xsd:simpleContent>

    </xsd:complexType>

</xsd:element>

PassWord节点的Type属性可以有如下值

描述

wsse:PasswordText(缺省)

用户名的实际密码。

wsse:PasswordDigest

用户名密码摘要。值为 UTF8 编码的密码的 base64 编码的 SHA1 散列值。

示例:

<S:Envelope xmlns:S="http://www.w3.org/2001/12/soap-envelope" xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/04/secext">

    <S:Header>

        ...

        <wsse:Security>

            <wsse:UsernameToken>

                <wsse:Username>Zoe</wsse:Username>

                <wsse:Password>ILoveDogs</wsse:Password>

            </wsse:UsernameToken>

        </wsse:Security>

        ...

    </S:Header>

    ...

</S:Envelope>

3.2 二进制安全性令牌

任何基于 XML 的安全性令牌都可以在 <Security> 报头中指定。然而,二进制(例如 X.509证书和 Kerberos票据)或其它非 XML 格式都需要特殊的编码格式进行包含。

一个二进制安全性令牌有两个用于解释自身的属性。ValueType 属性表明安全性令牌是什么,比如说 Kerberos票据。EncodingType 表明安全性令牌如何被编码,例如使用 Base64Binary。

BinarySecurityToken 元素定义二进制编码的安全性令牌。编码过程用 EncodingType 属性指定,值类型和空间用 ValueType 属性指定。

注意:ValueType属性的类型xsd:QName表明类型定义在本xml作用域内

<xsd:element name="BinarySecurityToken">

    <xsd:annotation>

        <xsd:documentation>A security token that is encoded in binary</xsd:documentation>

    </xsd:annotation>

    <xsd:complexType>

        <xsd:simpleContent>

            <xsd:extension base="xsd:string">

                <xsd:attribute name="Id" type="xsd:ID" />

                <xsd:attribute name="ValueType" type="xsd:QName" />

                <xsd:attribute name="EncodingType" type="xsd:QName" />

                <xsd:anyAttribute namespace="##other" processContents="strict" />

            </xsd:extension>

        </xsd:simpleContent>

    </xsd:complexType>

</xsd:element>

ValueType取值

QName

描述

wsse:X509v3

X.509v3 证书

wsse:Kerberosv5TGT

Kerberos的 5.3.1 节中定义的 Kerberosv5 票据。这个 ValueType 在票据为赋予票据的票据(ticket granting ticket,TGT)时使用。

wsse:Kerberosv5ST

Kerberos的 5.3.1 节中定义的 Kerberosv5 票据。这个 ValueType 在票据为服务票据(service ticket,ST)时使用。

EncodingType取值

QName

描述

wsse:Base64Binary

XML Schema base 64 编码

wsse:HexBinary

XML Schema十六进制编码

示例:

<wsse:BinarySecurityToken xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/04/secext" Id="myToken" ValueType="wsse:X509v3" EncodingType="wsse:Base64Binary">

MIIEZzCCA9CgAwIBAgIQEmtJZc0...

</wsse:BinarySecurityToken>

注意:当在签名中使用 <BinarySecurityToken> 时(也就是说从 <ds:Signature> 元素引用它),不允许对属性或元素值中 QName 的名称空间前缀进行非授权的替换。如果确实需要使用自有的属性值,则需要声明私有属性的作用域,示例如下:

<wsse:BinarySecurityToken xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/04/secext" Id="myToken" ValueType="x:MyType" xmlns:x="http://fabrikam123.com/x" EncodingType="wsse:Base64Binary">

MIIEZzCCA9CgAwIBAgIQEmtJZc0...

</wsse:BinarySecurityToken>

3.3. SecurityTokenReference 元素

发送一组安全性令牌声明。有时候这些声明驻留在其它某些地方,需要接收的应用程序到指定的URL地址去获取。<SecurityTokenReference> 元素提供了一种引用 安全性令牌的可扩展机制。

<SecurityTokenReference Id="...">

  <Reference URI="..."/>

</SecurityTokenReference>

示例:

<wsse:SecurityTokenReference xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/04/secext">

  <wsse:Reference URI="http://www.fabrikam123.com/tokens/Zoe#X509token" />

</wsse:SecurityTokenReference>

注意:该元素还可以被用作 <ds:KeyInfo> 的一个直接子元素,用来表明从其它某些地方的安全性令牌检索密钥信息的暗示。在使用 XML 签名和 XML 加密时,我们特别推荐将 <SecurityTokenReference> 元素放在 <ds:KeyInfo> 内来引用用于签名或加密的 安全性令牌。

3.4 ds:KeyInfo

对于某些密钥类型(如 X.509 证书)来说,<ds:KeyInfo> 元素(来自 XML 签名)和 <BinarySecurityToken> 元素都可以用于传送密钥信息。<ds:KeyInfo> 元素虑及了不同密钥类型和将来的扩展性(秘钥检索)。

然而,在本规范中,如果密钥类型在 wsse规范第 4.2 节中很好地定义过,那么使用 <BinarySecurityToken> 就是我们推荐用于传送密钥信息的方式。

示例:使用该元素获取命名过的密钥的过程

<ds:KeyInfo Id="..." xmlns:ds="http://www.w3.org/2000/09/xmldsig#">

 <ds:KeyName>CN=Hiroshi Maruyama, C=JP</ds:KeyName>

</ds:KeyInfo>

3.5 ds:Signature

消息发送方可能希望让消息接收方能够决定消息是否在传输过程中更改过,并验证消息是由特定安全性令牌持有人发送的。

当 XML 签名与 <SecurityTokenReference> 元素同时使用时,消息签署人的安全性令牌可能被关联,而安全性令牌声明和消息之间会以应用程序估计的方式产生映射。

由于某些SOAP报头的不稳定性,发送者绝不能使用 XML 签名中定义的封装的签名转换。相对,消息应该显式包括要签署的必要元素。类似地,发送方绝不能使用 XML 签名中定义的封装签名。

本规范虑及多个签名附加在消息中的情况,这时每个签名都引用不同、甚至重叠的消息部分。这对于很多分布式应用程序都是很重要的,在这些应用程序程序中,消息要经过多个处理阶段。举例来说,发送方可能提交一个包含 orderID 报头的订单。发送方签署 orderID 报头和请求的主体(订单的内容)。当订单处理子系统收到这个时,它可能向报头插入一个 shippingID。发出订单的子系统然后会签署(最少)orderID 和 shippingID,可能还有请求主体。然后当运输部门处理和交付该订单后,可能会附加一个 shippedInfo 报头。运输部门将签署(最少)shippedInfo 和 shippingID,可能还有请求主体,然后将消息转发给记帐部门进行处理。记帐部门可以验证签名并决定订单的有效信任链,以及各个角色所做的事情。

所有依从的实现都必须能够处理 <ds:Signature> 元素。

4.5.1 算法

WS-Security 规范建立在 XML 签名的基础之上,因此具有与 XML 签名规范中指定的相同的算法需求。

下面的表描述了 WS-Security 推荐的其它算法:

算法类型

算法

算法 URI

规范化

专用 XML 规范化,在签名hash前用于去除空格和其他格式

http://www.w3.org/2001/10/xml-exc-c14n

转换

XML 解密转换(XML Decryption Transformation)

http://www.w3.org/2001/04/decrypt

专用 XML 规范化算法使用“预先存在的签名”解决了一般规范化在名称空间有漏洞时存在的缺陷。

最后,如果发送方希望在加密前签署消息,他们应该使用 XML 签名的解密转换( Decryption Transformation for XML Signature)

4.5.2 签署消息

<Security> 报头块用于在 SOAP信封中传送符合 XML 签名规范的签名,为了签署 SOAP信封中的一个或多个元素。<Security> 报头块中的单独的 SOAP信封中可以添加多个签名条目。发送方应该注意签署消息的所有重要元素,但一定要注意创建的策略不会签署消息在传送过程中可能被合理更改的部分。

SOAP应用程序必须满足下面的条件:

  1. 应用程序必须能够处理 XML 签名规范中定义的所需元素。
  2. 要向 <Security> 报头块添加签名,应该预先考虑与 XML 签名规范一致的 <ds:Signature> 元素,下来才是已有的 <Security> 报头块的内容。也就是说,新信息要在旧信息之前(优先)。签名中包含的所有 <ds:Reference> 元素都应该引用包含它的 SOAP信封内(或附件中)的资源。

如 XML 签名规范中所示, XPath过滤可以用于指定将签署的对象。然而,因为 SOAP消息交换模型允许中介体应用程序修改信封(如添加或删除报头块), XPath过滤在消息传递之后并不总能得到相同对象。使用 XPath过滤时应该注意避免因为这种修改导致后来的验证失败。

中介体应用程序修改的问题不仅仅在 XPath 处理中才会发生。由于规范化和 分类的原因,数字签名是这种关系的特别脆弱的例子。如果消息处理整体要保持健壮,中介体必须注意转换不会出现在数字签名组件的范围中。

鉴于和名称空间有关的安全性注意事项,本规范强烈推荐您使用提供相同或更多保护的“ 专用 XML 规范化(Exclusive XML Canonicalization)”算法或其它标准化算法。

4.5.3 验证完整性

如果发生下列情况,<Security> 报头块中 <ds:Signature> 条目的验证就会失败:

  1. 条目内容的句法不遵守本规范,或者
  2. 根据 XML 签名的核心验证,条目中包含的 签名的验证失败,或者
  3. 应用自己的信任策略的应用程序因为某种原因拒绝消息(例如, 签名由非信任的密钥创建—验证前两个步骤只会执行对 签名加密的验证)。

如果签名验证失败,那么应用程序可能会使用 第 6 节中定义的错误代码向发送者报告失败情况。

4.5.4 示例

下面的样本消息举例说明了完整性和安全性令牌的使用(一条完整的符合wsse标准的soap报文)。对于本示例,我们使用了假定的“RoutingTransform”,它选择不变的路由报头以及消息主体。

<?xml version="1.0" encoding="utf-8" ?>

<S:Envelope xmlns:S="http://www.w3.org/2001/12/soap-envelope" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/04/secext" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">

  <S:Header>

    <m:path xmlns:m="http://schemas.xmlsoap.org/rp">    <!--rp规范,标识路由信息-->

      <m:action>http://fabrikam123.com/getQuote</m:action>

      <m:to>http://fabrikam123.com/stocks</m:to>

      <m:from>mailto:[email protected]</m:from>

      <m:id>uuid:84b9f5d0-33fb-4a81-b02b-5b760641c1d6</m:id>

    </m:path>

    <wsse:Security>

      <wsse:BinarySecurityToken ValueType="wsse:X509v3" EncodingType="wsse:Base64Binary" Id="X509Token">

        MIIEZzCCA9CgAwIBAgIQEmtJZc0rqrKh5i...

      </wsse:BinarySecurityToken>

      <ds:Signature> <!--xml签名-->

        <ds:SignedInfo>

          <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />

          <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />

          <ds:Reference>

            <ds:Transforms>

              <ds:Transform Algorithm="http://...#RoutingTransform" />

              <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />

            </ds:Transforms>

            <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />

            <ds:DigestValue>EULddytSo1...</ds:DigestValue>

          </ds:Reference>

        </ds:SignedInfo>

        <ds:SignatureValue>

          BL8jdfToEb1l/vXcMZNNjPOV...

        </ds:SignatureValue>

        <ds:KeyInfo>

          <wsse:SecurityTokenReference>

            <wsse:Reference URI="#X509Token" />

          </wsse:SecurityTokenReference>

        </ds:KeyInfo>

      </ds:Signature>

    </wsse:Security>

  </S:Header>

  <S:Body>

    <tru:StockSymbol xmlns:tru="http://fabrikam123.com/payloads">

      QQQ

    </tru:StockSymbol>

  </S:Body>

</S:Envelope>

4.6 子元素加密

本规范允许通过发送方和接收方共享的通用对称密钥或消息中带有的加密形式的密钥,对消息主体块、报头块、任意这些子结构和附件的组合进行加密。简单说就是不对整个xml加密,支队部分敏感信息加密。

为了实现这种灵活性,我们利用了 XML 加密(XML Encryption)标准。我们将特别描述如何在 <Security> 报头块中使用三个元素(下面列出的和 XML 加密中定义的)。当发送方或中介体使用 XML 加密对部分 SOAP消息加密时,它们会向 <Security> 报头块添加子元素。此外,加密方还必须预先考虑在 <Security> 报头块中使用子元素作为应该对加密部分解密的目标接收方。组合加密部分消息和添加其中一个引用加密部分的子元素的过程以后就被称为 加密步骤。子元素应该有足够信息,好让接收方可以识别消息的那些部分要由接收方解密。

4.6.1 xenc:ReferenceList

在加密 SOAP消息内的元素或元素内容时,您可以使用 XML 加密的 <xenc:ReferenceList> 元素来创建加密部分的证明,它被表示为信封内的 <xenc:EncryptedData> 元素。(注:意思是说<xenc:ReferenceList>用来声明要加密的xml局部数据,而加密后的数据封装在 <xenc:EncryptedData>中)这个加密步骤要加密的元素或元素内容必须根据 XML 加密由对应的 <xenc:EncryptedData> 替换。该加密步骤创建的所有 <xenc:EncryptedData> 元素都应该列在 <xenc:ReferenceList> 元素的 <xenc:DataReference> 元素中。

尽管在 XML 加密中,<xenc:ReferenceList> 最初被设计为在 <xenc:EncryptedKey> 元素中使用(这表明所有被引用的 <xenc:EncryptedData> 元素都用同一个密钥加密),本规范允许同一个 <xenc:ReferenceList> 引用的 <xenc:EncryptedData> 元素在不同步骤中加密。每个加密密钥都可以在 <xenc:EncryptedData> 内的 <ds:KeyInfo> 中指定。

<xenc:ReferenceList> 子元素有用的典型情况是,发送方和接收方都使用共享的秘密密钥。下面举例说明了这个子元素的使用:

<S:Envelope xmlns:S="http://www.w3.org/2001/12/soap-envelope" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/04/secext" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">

  <S:Header>

    <wsse:Security>

      <xenc:ReferenceList>

        <xenc:DataReference URI="#bodyID" />

      </xenc:ReferenceList>

    </wsse:Security>

  </S:Header>

  <S:Body>

    <xenc:EncryptedData Id="bodyID">

      <ds:KeyInfo>

        <ds:KeyName>CN=Hiroshi Maruyama, C=JP</ds:KeyName>

      </ds:KeyInfo>

      <xenc:CipherData>

        <xenc:CipherValue>...</xenc:CipherValue>

      </xenc:CipherData>

    </xenc:EncryptedData>

  </S:Body>

</S:Envelope>

4.6.2 xenc:EncryptedKey

加密步骤涉及到使用密钥(它接着会被接收方的密钥加密并嵌入到消息中)加密 SOAP信封中的元素或元素内容时,就可以使 <xenc:EncryptedKey> 来传送这种加密密钥了。该子元素应该有一个证明(也就是 <xenc:ReferenceList> 元素),用来让接收方了解要用这个密钥(如果存在的话)解密的部分。要用这个加密步骤加密的元素或元素部分必须根据 XML 加密由对应的 <xenc:EncryptedData> 替换。所有这个步骤创建的 <xenc:EncryptedData> 元素都应该列在该子元素内的 <xenc:ReferenceList> 元素中。

这种构建方法在通过随机生成的对称密钥(该密钥接着由接收方的公共密钥加密)完成加密时很有用。下面举例说明了这个元素的使用:

<S:Envelope xmlns:S="http://www.w3.org/2001/12/soap-envelope" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/04/secext" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">

  <S:Header>

    <wsse:Security>

      <xenc:EncryptedKey>

        <xenc:EncryptionMethod Algorithm="..." />

        <ds:KeyInfo>

          <ds:KeyName>CN=Hiroshi Maruyama, C=JP</ds:KeyName>

        </ds:KeyInfo>

        <xenc:CipherData>

          <xenc:CipherValue>...</xenc:CipherValue> <!--直接发送秘钥-->

        </xenc:CipherData>

        <xenc:ReferenceList>

          <xenc:DataReference URI="#bodyID" />

        </xenc:ReferenceList>

      </xenc:EncryptedKey>

    </wsse:Security>

  </S:Header>

  <S:Body>

    <xenc:EncryptedData Id="bodyID">

      <ds:KeyInfo>

        <ds:KeyName>CN=Hiroshi Maruyama, C=JP</ds:KeyName>

      </ds:KeyInfo>

      <xenc:CipherData>

        <xenc:CipherValue>...</xenc:CipherValue>

      </xenc:CipherData>

    </xenc:EncryptedData>

  </S:Body>

</S:Envelope>

4.6.3 xenc:EncryptedData

在某些情况下,有关安全性的信息是以完全加密的形式提供的,或者加密时非 XML 附件会被加密。 XML 加密的 <xenc:EncryptedData> 元素可以用在这种情况下。对加密附件的每个部分来说,都需要一个加密步骤;那就是,对于每个要加密的附件,都必须遵守下列规则添加一个 <xenc:EncryptedData> 子元素(请注意,步骤 2 到 4 只有在 MIME 类型由附件使用时才适用)。

  1. 附件的内容必须被加密八位串代替。
  2. 被替换的 MIME 部分的媒体类型必须是 application/octet-stream。
  3. 附件的原始媒体类型必须在 <xenc:EncryptedData> 元素的 MimeType 属性中声明。
  4. 加密的 MIME 部分必须由 <xenc:CipherReference> 元素引用,其中 URI 指向 MIME 部分,cid: 为 URI 的模式组件。

下面举例说明了使用该元素表明加密附件的方法:

<S:Envelope xmlns:S="http://www.w3.org/2001/12/soap-envelope" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/04/secext" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">

  <S:Header>

    <wsse:Security>

      <xenc:EncryptedData MimeType="image/png">

        <xenc:EncryptionMethod Algorithm="foo:bar" />

        <ds:KeyInfo>

          <ds:KeyName>CN=Hiroshi Maruyama, C=JP</ds:KeyName>

        </ds:KeyInfo>

        <xenc:CipherData>

          <xenc:CipherReference URI="cid:image" />

        </xenc:CipherData>

      </xenc:EncryptedData>

    </wsse:Security>

  </S:Header>

  <S:Body></S:Body>

</S:Envelope>

4.6.4. 处理规则

使用上述其中一种子元素对 SOAP消息加密的部分或附件必须符合 XML 加密规范。加密的 SOAP消息必须还是一个有效的 SOAP信封。消息的创建者绝不能加密 <S:Envelope><S:Header> <S:Body> 元素,但可以加密 <S:Header> <S:Body> 元素的子元素。如果它们的目标都是同一个接收方,那么就可以向单独的 <Security> 报头块添加多个步骤的加密。

当要加密 SOAP信封中的元素或元素内容(例如 <S:Body> 的内容)时,它必须根据 XML 加密 <xenc:EncryptedData> 替换,而且它应该从此加密步骤创建的 <xenc:ReferenceList> 元素引用。此规范允许在附件中存放加密八位流。举例来说,如果 <S:Body> 元素内出现的 <xenc:EncryptedData> 有引用附件的 <xenc:CipherReference>,那么解密八位流就替换 <xenc:EncryptedData>。然而,如果 <enc:EncryptedData> 的位置在 <Security> 报头块中,而它引用附件,那么解密八位流就必须替换附件中的加密八位流。

注:签名和加密的顺序,一般是先签名后加密,签名验证要求对解密后原文,这样可以保证接收者既知道怎么解密又防止信息篡改

加密

创建符合此规范的加密 SOAP消息的一般步骤(非标准化的)如下所示(请注意,我们推荐使用 <xenc:ReferenceList>)。

  1. 创建新的 SOAP信封。
  2. 根据加密类型,在 <Security> 报头块中创建 <xenc:ReferenceList> 子元素、<xenc:EncryptedKey> 子元素或 <xenc:EncryptedData> 子元素(请注意,SOAP “actor”和“mustUnderstand”属性是否不同,不同就需要一个新的报头表)。
  3. 定位要加密的数据项,也就是 XML 元素、目标 SOAP 信封中的元素内容和附件。
  4. 如下所示加密数据:对于目标 SOAP信封中的每个 XML 元素或元素内容来说,根据 XML 加密规范的处理规则进行加密。每个已选择的原始元素或元素内容都由最后的 <xenc:EncryptedData> 元素删除和替换。对附件来说,内容则必须由加密的密码数据替换,如 章节 4.5.3.中所示。
  5. <xenc:EncryptedData> 元素中可选的 <ds:KeyInfo> 可以引用另一个 <ds:KeyInfo> 元素。请注意,如果加密是基于附加的安全性令牌的,那么就应该向 <ds:KeyInfo> 元素添加一个 <SecurityTokenReference> 元素以便于定位它。
  6. 创建一个引用生成的 <xenc:EncryptedData> 元素的 <xenc:DataReference> 元素。向 <xenc:ReferenceList> 添加 <xenc:DataReference>。

解密

当收到带有加密报头条目的 SOAP信封时,对于每个加密报头来说都应该进行下面的一般步骤(非标准的):

  1. 定位要解密的 <xenc:EncryptedData> 项(可能使用 <xenc:ReferenceList>)。
  2. 如下进行解密:对于目标 SOAP信封中的每个元素,根据 XML 加密规范的处理规则和上面列出的处理规则进行解密。
  3. 如果解密数据是附件的一部分而且使用了 MIME 类型,那么将附件的 MIME 类型改为原始 MIME 类型(如果存在)。
  4. 如果因为某种原因解密失败,应用程序就可以使用 第 6 节中定义的错误代码向发送方报告失败情况。

5 扩展示例

(001)<?xml version="1.0" encoding="utf-8" ?>

(002)<S:Envelope xmlns:S="http://www.w3.org/2001/12/soap-envelope" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/04/secext" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">

(003)  <S:Header>

(004)    <m:path xmlns:m="http://schemas.xmlsoap.org/rp/">

(005)      <m:action>http://fabrikam123.com/getQuote</m:action>

(006)      <m:to>http://fabrikam123.com/stocks</m:to>

(007)      <m:from>mailto:[email protected]</m:from>

(008)      <m:id>uuid:84b9f5d0-33fb-4a81-b02b-5b760641c1d6</m:id>

(009)    </m:path>

(010)    <wsse:Security>

(011)      <wsse:BinarySecurityToken ValueType="wsse:X509v3" Id="X509Token" EncodingType="wsse:Base64Binary">

(012)        MIIEZzCCA9CgAwIBAgIQEmtJZc0rqrKh5i...

(013)      </wsse:BinarySecurityToken>

(014)      <xenc:EncryptedKey>

(015)        <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />

(016)        <ds:KeyInfo>

(017)          <ds:KeyName>CN=Hiroshi Maruyama, C=JP</ds:KeyName>

(018)        </ds:KeyInfo>

(019)        <xenc:CipherData>

(020)          <xenc:CipherValue>

(021)            d2FpbmdvbGRfE0lm4byV0...

(022)          </xenc:CipherValue>

(023)        </xenc:CipherData>

(024)        <xenc:ReferenceList>

(025)          <xenc:DataReference URI="#enc1" />

(026)        </xenc:ReferenceList>

(027)      </xenc:EncryptedKey>

(028)      <ds:Signature>

(029)        <ds:SignedInfo>

(030)          <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />

(031)          <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />

(032)          <ds:Reference>

(033)            <ds:Transforms>

(034)              <ds:Transform Algorithm="http://...#RoutingTransform" />

(035)              <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />

(036)            </ds:Transforms>

(037)            <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />

(038)            <ds:DigestValue>

(039)              LyLsF094hPi4wPU...

(040)            </ds:DigestValue>

(041)          </ds:Reference>

(042)        </ds:SignedInfo>

(043)        <ds:SignatureValue>

(044)          Hp1ZkmFZ/2kQLXDJbchm5gK...

(045)        </ds:SignatureValue>

(046)        <ds:KeyInfo>

(047)          <wsse:SecurityTokenReference>

(048)            <wsse:Reference URI="#X509Token" />

(049)          </wsse:SecurityTokenReference>

(050)        </ds:KeyInfo>

(051)      </ds:Signature>

(052)    </wsse:Security>

(053)  </S:Header>

(054)  <S:Body>

(055)    <xenc:EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" Id="enc1">

(056)      <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#3des-cbc" />

(057)      <xenc:CipherData>

(058)        <xenc:CipherValue>

(059)          d2FpbmdvbGRfE0lm4byV0...

(060)        </xenc:CipherValue>

(061)      </xenc:CipherData>

(062)    </xenc:EncryptedData>

(063)  </S:Body>

(064)</S:Envelope>

让我们来回顾本示例中一些关密钥的部分:

  • 行(003)到(053)包含 SOAP 消息报头。
  • 行(004)到(009)指定 消息路由信息(如 WS-Routing 定义的)。在本示例中,我们发送消息到 http://fabrikam123.com/stocks 服务,请求“getQuote”操作。
  • 行(010)到(052)表示 <Security> 报头块。它包含消息的与安全性相关的信息。
  • 行(011)到(013)指定与消息关联的安全性令牌。在本示例中,它指定按 Base64 编码的 X.509证书。行(012)指定该证书的实际 Base64 编码。
  • 行(014)到(027)指定用于加密消息主体的密钥。因为这是一个对称密钥,所以它是以加密形式传送的。行(015)定义用于加密密钥的算法。行(016)到(018)指定用于加密对称密钥的密钥的名称。行(019)到(022)指定对称密钥实际的加密形式。行(023)到(025)识别消息中使用该对称密钥的加密块。在本示例中,它只用于加密消息主体(Id="enc1")。
  • 行(027)到(049)指定数字签名。在本示例中,签名是基于X.509证书的。行(028)到(040)表明签署什么。行(029)表明规范化算法(本示例中是排它的)。行(030)表明签名算法(在本示例中是 sha1 上的 rsa)。
  • 行(032)到(041)标识正在被签署的消息部分。行(033)特别标识"转换"。这个假定的转换将选择路由报头和消息主体不变的部分。行(034)指定行(033)所选择的消息部分上要使用的规范化算法。行(036)表明规范化数据上的分类算法使用。行(037)指定规范化数据上的指定算法得出的分类值。
  • 行(043)到(045)表明实际的签名值 — 在行(042)指定。
  • 行(053)到(050)表明用于签名的密钥。在本示例中,它是消息中包括的 X.509证书。行(046)提供对行(011)到(013)的 URI 链接。
  • 消息主体是由行(055)到(062)表示的。
  • 行(052)到(063)表示加密的元数据和使用 XML 加密的消息主体的形式。行(053)表明“元素值”将被替换,并标识加密。行(054)指定加密算法 — 在本示例中为 Triple-DES。行(055)到(058)包含实际的密码文本(也就是加密的结果)。请注意,我们不包括对密钥的引用作为引用加密的密钥 — 行(024)。

6 错误码

在很多情况下,处理安全性信息时都会出现 错误。例如:

  • 无效或不支持的安全性令牌、签名或加密类型
  • 无效、非授权或不可授权的安全性令牌
  • 无效签名
  • 解密失败
  • 所引用的安全性令牌无法使用

这些错误可以分为两 类:不支持的和失败的。

对于不支持的错误情况来说,接收者可以提供响应,告知发送者支持的格式等等。

对于失败的错误来说,接收者可以选择不响应,因为这可以算是拒绝服务(Denial of Service,DOS)或加密攻击的一种形式。

结合签名和加密失败来减少某些类型的攻击。

如果失败返回到发送者,那么必须使用 SOAP的“错误(Fault)”机制来报告错误。

下面的表描述了预定义的安全性错误代码。

错误的“不支持”类为:

出现的错误

错误代码

提供了不支持的令牌

wsse:UnsupportedSecurityToken

使用了不支持的签名或加密算法

wsse:UnsupportedAlgorithm

错误的“失败”类为:

出现的错误

错误代码

处理 <Security> 报头时发现错误。

wsse:InvalidSecurity

提供了无效的安全性令牌

wsse:InvalidSecurityToken

安全性令牌无法被验证或授权

wsse:FailedAuthentication

签名或解密是无效的

wsse:FailedCheck

引用的安全性令牌无法检索

wsse:SecurityTokenUnavailable

 

参考资料:

[1] w3c-xml schema
[2] "RELAX NG"--Eric van der Vlist
[3] ws-secure中翻译
[4] xml-signature

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章