65.9K
CodeProject 正在变化。 阅读更多。
Home

深入了解 SecureConversation – 第二部分

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (3投票s)

2006 年 11 月 17 日

CPOL

6分钟阅读

viewsIcon

31195

深入探讨增强型 Web 服务的安全协议,第二部分:分析响应消息。

引言

本文的第一部分中,我们分析了 Cardspace 与我自己的安全令牌服务(STS),也称为身份提供程序,实现之间的 RST/RSTR 交换的请求消息。在第二部分中,我们将深入探讨 STS 响应我们之前分析的请求消息而发送回来的响应消息。

与第一部分一样,我们只关注保护 RST/RSTR 数据的安全协议。此协议用于在新版 Web 服务规范中传输多种类型的交换。我以后会写另一篇文章来介绍用于将 SAML 令牌从 STS 传输到请求方的 RST/RSTR。

背景

本文不涉及任何代码,但是假设您对 XML 有深入的了解,并且对基本的加密学有所理解,例如使用对称和非对称算法进行加密和签名。我附带了一个小程序,可以帮助您理解本文中使用的加密学基础。

如果您还没有阅读本文的第一部分,我强烈建议您阅读,因为我们将使用第一部分中详细介绍的概念。

第二部分:包含 RSTR(RequestSecurityTokenResponse)的响应 SOAP 消息

SOAP 消息的结构

您可以通过第一部分的相同章节来获取 SOAP 消息结构的描述。与请求消息一样,分析整个消息所需的许多有用信息都包含在标头中的 Security 元素里。我们将首先介绍如何解密 Security 元素中的加密内容。

解密标头中的加密元素

与请求消息一样,我们必须获取整个消息中所有加密数据的列表。这通过 Security 中的 ReferenceList 元素给出。此元素如下所示。

<e:ReferenceList xmlns:e="http://www.w3.org/2001/04/xmlenc#">
  <e:DataReference URI="#_3" />
  <e:DataReference URI="#_6" />
</e:ReferenceList>

在此消息中,我们有两个加密元素。让我们先关注 ID 为 "_6" 的元素,它位于 Security 元素中。正如我们在第一部分中看到的,EncryptedData 包含一个 KeyInfo,它有助于查找用于加密数据的密钥。整个 EncryptedData 元素在列表 1 中进行了描述。

列表 1

<e:EncryptedData 
        Type="http://www.w3.org/2001/04/xmlenc#Element" Id="_6" 
        xmlns:e="http://www.w3.org/2001/04/xmlenc#">
    <e:EncryptionMethod 
        Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc" />
  <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
    <o:SecurityTokenReference>
            <o:Reference URI="#_4" />
    </o:SecurityTokenReference>
    </KeyInfo>
    <CipherData xmlns="http://www.w3.org/2001/04/xmlenc#">
    <CipherValue>L9uCbEDhVjcB4gTBqC3GtyaiGGY8P7...
               oDJ7pB21bAA48xoLzk2ks</CipherValue>
    </CipherData>
</e:EncryptedData>

如果我们查看 EncryptionMethod 元素,我们会发现数据已使用 128 位密钥的对称 AES 算法加密。因此,我们需要做的第一件事是找到用于加密的密钥,以便解密数据。此信息由 KeyInfo 元素提供。此元素引用了一个 ID 为 "_4" 的元素。在 Security 元素中查找,我们可以发现它指向以下 DerivedKeyToken 元素。

<sc:DerivedKeyToken u:Id="_4" 
    xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-
             200401-wss-wssecurity-utility-1.0.xsd" 
    xmlns:sc="http://schemas.xmlsoap.org/ws/2005/02/sc">
  <o:SecurityTokenReference>
    <o:KeyIdentifier 
       ValueType="http://docs.oasis-open.org/wss/oasis-
                  wss-soap-message-security-1.1#EncryptedKeySHA1">
      UbPUL5eLKdw25Xptln4DOGN3YLI=
    </o:KeyIdentifier>
  </o:SecurityTokenReference>
  <sc:Offset>0</sc:Offset>
  <sc:Length>16</sc:Length>
  <sc:Nonce>i2uYqtgSQCE/KE7C4E86UQ==</sc:Nonce>
</sc:DerivedKeyToken>

这种元素类型在本文的第一部分中已经见过。DerivedKeyToken 元素包含计算派生密钥的信息。用于计算此密钥的算法是 PSHA1,它需要一个主密钥、一个随机数和一个标签。标签值由 Microsoft 固定为字符串值“WS-SecureConversationWS-SecureConversation”。SecurityTokenReference 用于获取主密钥值。在请求消息中,主密钥被引用为 EncryptedKey。此主密钥实际上由两个消息共享。响应消息将由请求方处理,请求方是创建请求消息的方,因此知道它生成的该主密钥。

SecurityTokenReference 的目的是让请求方能够检查 STS 使用的密钥是否是请求方自己生成的密钥。

SecurityTokenReference 包含一个 KeyIdentifier,其 ValueType 属性指示我们正在查找的密钥的引用是 EncryptedKeySHA1。这意味着 Base64 值 UbPUL5eLKdw25Xptln4DOGN3YLI= 代表了在请求消息中发送的加密密钥值的 SHA1。如果您参考第一部分,该值为 XsApZde4j3w35HGt…YVHkbY0MFZIg=。请求方必须保留此加密数据并将其映射到主密钥值。与使用 RSA 加密一样,对于相同的数据,密文总是不同的,因此请求方无法再次加密主密钥来获得加密值。当然,要进行计算,您必须首先获取 Base 64 数据的二进制值。

您可以在第一部分的文章中使用的工具来检查这一点。

有了主密钥,现在就可以计算派生密钥并使用它来解密加密元素中的数据。应用解密后,您应该会得到列表 2 中的数据。这些数据是 ASCII 值,实际上是消息的 Signature 元素。

列表 2

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
  <SignedInfo>
    <CanonicalizationMethod 
       Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
    <SignatureMethod 
       Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1" />
    <Reference URI="#_0">
      <Transforms>
        <Transform 
           Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
      </Transforms>
      <DigestMethod 
         Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
      <DigestValue>cf8q2Vw2rW5blihu0xWaxCdU4QA=</DigestValue>
    </Reference>
    <Reference URI="#_1">
      <Transforms>
        <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
      </Transforms>
      <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
      <DigestValue>LDb2+mKJ9h0YUEQ2IILUtKjSWGg=</DigestValue>
    </Reference>
    <Reference URI="#uuid-8346502e-ebb7-b631-0704-403dd21ca6ec-1">
      <Transforms>
        <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
      </Transforms>
      <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
      <DigestValue>fJ9Jk5L5Du0pY6FSIQnuBRKtVmI=</DigestValue>
    </Reference>
    <Reference URI="#_5">
      <Transforms>
        <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
      </Transforms>
      <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
      <DigestValue>SjeSg51ZvqDFfu46wsHK2+QmZEo=</DigestValue>
        </Reference>
    </SignedInfo>
  <SignatureValue>7ddH6wlhQNJPw6VRMORxP6eD37Q=</SignatureValue>
  <KeyInfo>
    <o:SecurityTokenReference 
         xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-
                  200401-wss-wssecurity-secext-1.0.xsd">
      <o:Reference URI="#_4" />
    </o:SecurityTokenReference>
  </KeyInfo>
</Signature>

解密正文中的加密数据

既然我们已经解密了 Signature 元素,解密正文将易如反掌!BodyEncryptedData 元素如下所示:

<e:EncryptedData 
      Type="http://www.w3.org/2001/04/xmlenc#Content" 
      Id="_3" xmlns:e="http://www.w3.org/2001/04/xmlenc#">
  <e:EncryptionMethod 
     Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc" />
  <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
    <o:SecurityTokenReference 
         xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-
                  200401-wss-wssecurity-secext-1.0.xsd">
      <o:Reference URI="#_4" />
    </o:SecurityTokenReference>
  </KeyInfo>
  <CipherData xmlns="http://www.w3.org/2001/04/xmlenc#">
    <CipherValue>83suvxZAJ+4hOeo/baEFfdu20yKkU4unm1QJ4N9
                  WrUVOa...BVNOKR5yumvi/aQ==</CipherValue>
  </CipherData>
</e:EncryptedData>

如果我们查看 KeyInfo,可以看到它引用了同一个密钥,这意味着我们只需要使用我们计算出的派生密钥来解密 Signature。对数据运行 AES128 解密算法将为我们提供一些 ASCII 数据,即 RequestSecurityTokenResponse XML 元素。该元素由 STS 响应请求消息正文中解密的 RST 而构建。

接下来需要做的是验证请求方收到的消息的完整性。之前,我们解密了一个 Signature 元素。该元素包含用于验证它的信息。

验证签名

如果您参考请求消息中的 Signature 元素,并在本文第一部分中对其进行了分析,您会发现它的结构非常相似。由于没有进一步的兴趣来详细介绍 Signature 的验证过程,您可以在本文第一部分中找到它。

关注点

在这两部分中,我们已经看到了大量的概念和信息。WCF 完全隐藏了 WS-* 协议,使安全功能的使用就像配置文件中的一行 XML 一样简单。然而,您可以看到幕后发生了许多事情。当您激活安全功能,或者需要处理互操作性(就像我需要做的那样)时,理解实际发生的情况尤为重要。

因此,我希望本文能引起您学习 WCF 中使用的安全协议的兴趣。当然,这只是一个特定互操作性案例的研究,但我认为它可以帮助您更好地理解如何在 WCF 中使用安全性,就像它通过撰写本文帮助我更清楚地认识到这些功能一样。

© . All rights reserved.