BinarySecurityToken
在WS-Security规范出现之前,针对Web Service或者其他的分布式技术并不是没有安全协议来保证它们的安全。只是这些协议一旦跨越了企业边界往往会受到防火墙的影响,而不再起作用。在WS-Security中,并没有抛弃这些现有的协议,而是将这些Binary的Security Token通过Encoding的方式集成到XML元素中,从而在Web Service中仍然能使用这些经典的安全协议,并利用SOAP消息穿越防火墙的特性,使它们适用于新的环境。这类Security Token在WS-Security中被称为BinarySecurityToken,目前仅支持X509v3 Certificate和Kerberos两种,但是利用XML的高度扩展性,用户可以定义自己的BinarySecurityToken。
下面是BinarySecurityToken的标准格式:
<wsse:BinarySecurityToken wsu:Id=...
EncodingType=...
ValueType=...>
...Binary Data ...
<wsse:BinarySecurityToken/>
其中EncodingType属性指定将Binary数据Encoding到XML中的方法(常用Base64); ValueType属性指定BinarySecurityToken的类型(比如X509v3); 元素内容则是经过Encoding的BinaryToken的内容。
使用X.509 Token来保证消息安全在介绍UsernameToken的文章最后已经提到。如果把UsernameToken从那个例子中去除,就变成了WSE中已经实现了的AnonymousForCertificate。
下图就是AnonymousForCertificate对SOAP Envelop的扩展结构。
可以看出它和UsernameForCertificate非常相似,仅仅缺少了被加密的UsernameToken元素. 这点也正如它的名字所描述的一致,即使用这种方式的用户对于Service来说是匿名的,也就没有用户鉴别的概念. 这恰好适用于那些仅仅需要保证消息安全而不需要验证用户身份的应用. 在介绍UsernameForCertificate的时候,并没有详细说明对X509Certificate Token的引用, 这里做一些补充. 先来回顾一下之前在是如何引用X509Certificate Token. 从示意图上我们也可以看出X509Certificate Token并没有象UsernameToken那样被包含在Request Security Head中, 为什么? 原因很简单, 因为这里的X509证书并不是Client自己的证书,而是Service的证书(根据对称密钥的原理,加密需要使用消息接受方的公钥). 以下是采用KeyIdentifier来引用Service的证书的方式.
<xenc:EncryptedKey wsu:id="userSysmetricKey">
…
<ds:KeyInfo>
<wsse:SecurityTokenReference>
<wsse:KeyIdentifier
ValueType="...oasis-wss-soap-message-security-1.1#ThumbPrintSHA1">
LKiQ/CmFrJDJqCLFcjlhIsmZ/+0=
</wsse:KeyIdentifier>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
…
</xenc:EncryptedKey>
对于这种使用消息接受方X509证书加密的应用场景, 在WS-Security1.1规范中还定义了另一种引用证书的方法---X509IssuerSerial.
<xenc:EncryptedKey wsu:id="userSysmetricKey">
…
<ds:KeyInfo>
<wsse:SecurityTokenReference>
<ds:X509Data>
<ds:X509IssuerSerial>
<ds:X509IssuerName>
DC=ACMECorp, DC=com
</ds:X509IssuerName>
<ds:X509SerialNumber>12345678</ds:X509SerialNumber>
</ds:X509IssuerSerial>
</ds:X509Data>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
….
</xenc:EncryptedKey>
使用AnonymousForCertificate的方法最大的缺陷就是无法实现用户的身份鉴别, 然而在大多数的应用中这个功能是不可豁缺的. 使用UsernameForCertificate可以达到鉴别用户身份的目的, 不过它一般用于保证个人用户和企业之间的安全. 而企业与企业之间常采用X509证书来达到互相的信任.一方面因为使用X509证书的安全性要高于Username&Password, 另一方面从现实的角度你不可能为每个企业分配一个用户名密码. 于是就会在SOAP Head中出现两个X509证书, 从而实现相互认证. 这也是WSE中MutualCertificate所要实现的功能.
在采用两个X509证书来实现相互认证中, 比AnonymousForCertificate方式多出了用户的X509证书. 而加入它的原因就是要利用用户的私钥来签名消息, 从而让Service通过证书来鉴别用户的身份.下图就是MutualCertificate11对SOAP Envelop的扩展结构。
从中可以看出变化比较小,仅仅多出了一个用户X509 Certificate,并用它对原来的ds:Signature元素做了一次签名. 对应这副图的Soap Envelop如下:
<?xml version="1.0" encoding="utf-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2001/12/soap-envelope"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
xmlns:xenc="http://www.w3.org/2001/04/xmlenc"
xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility">
<SOAP-ENV:Header>
<wsse:Security
xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/secext">
<wsse:BinarySecurityToken
wsu:Id="userX509Cert"
ValueType="…#X509v3"
EncodingType="…#Base64Binary">
MIIEZzCCA9CgAwIBAgIQEmtJZc0…
</wsse:BinarySecurityToken>
<xenc:EncryptedKey wsu:id="userSysmetricKey">
<xenc:EncryptionMethod
Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
<ds:KeyInfo>
<wsse:SecurityTokenReference>
<wsse:KeyIdentifier
ValueType="...oasis-wss-soap-message-security-1.1#ThumbPrintSHA1">
LKiQ/CmFrJDJqCLFcjlhIsmZ/+0=
</wsse:KeyIdentifier>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>G2wDCq24FsgBGerE...</xenc:CipherValue>
</xenc:CipherData>
<xenc:ReferenceList>
<xenc:DataReference URI="#DiscountResponse"/>
</xenc:ReferenceList>
</xenc:EncryptedKey>
<ds:Signature wsu:id="originSignature">
<ds:SignedInfo>
<ds:CanonicalizationMethod
Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"/>
<ds:Reference URI="#DiscountedBookingForPartnersResponse">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>JwFsd3eQc0iXlJm5PkLh7...</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>BSxlJbSiFdm5Plhk...</ds:SignatureValue>
<ds:KeyInfo>
<wsse:SecurityTokenReference>
<wsse:Reference URI="#userSysmetricKey"
ValueType="...oasis-wss-soap-message-security-1.1#EncryptedKey"/>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
<ds:Signature>
<ds:SignedInfo>
...
<ds:Reference URI="#originSignature">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>FeGre4lWv1lY2Kn4LJkg9...</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>ADfkTeYsGen5Re4L...</ds:SignatureValue>
<ds:KeyInfo>
<wsse:SecurityTokenReference>
<wsse:Reference URI="#userX509Cert"
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body wsu:Id="DiscountedBookingForPartnersResponse">
<s:GetSpecialDiscountedBookingForPartnersResponse
xmlns:s="http://www.MyHotel.com/partnerservice ">
<xenc:EncryptedData
wsu:Id="DiscountResponse"
type="http://www.w3.org/2001/04/xmlenc#Element">
<xenc:EncryptionMethod
Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc "/>
<CipherData>
<CipherValue>XD6sFa0DrWsHdehrHdhcW0x...</CipherValue>
</CipherData>
</xenc:EncryptedData>
</s:GetSpecialDiscountedBookingForPartnersResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
和加密引用证书一样, 在WS-Security1.1中为签名也定义了3种引用方式.第一种就是上述的引用BinarySecurityToken. 第二种同加密所用的第二种方法一样采用X509IssuerSerial.第三种是KeyIdentifier, 只不过与加密所用的KeyIdentifier的类型不同,下面是使用KeyIdentifier做签名的引用的示例:
<ds:Signature
…
<ds:KeyInfo>
<wsse:SecurityTokenReference>
<wsse:KeyIdentifier EncodingType="...#Base64Binary"
ValueType="...#X509SubjectKeyIdentifier">
MIGfMa0GCSq…
</wsse:KeyIdentifier>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>