SOAP 消息中的 <wsse:Security> 头部保存有所有运行时安全配置信息和签名数据。第一个项是 <wsu:Timestamp>,在 WS-SecurityPolicy 配置中被请求。时间戳包含了两个时间值:创建时间和过期时间。这两个值在本例中为 5 分钟的时间间隔,这是 Rampart 的默认设置。(可以在 Rampart 策略配置中修改这两个值)。这两个值之间的时间量稍微有些随意,但是 5 分钟是一个比较合理的值 — 足够处理客户机与服务器之间存在的适当的时钟偏移(系统时钟之间的差异),但是同时也能够限制利用消息进行重播攻击。在时间戳之后,安全头部的下一个项是 <wsse:BinarySecurityToken>。这个安全令牌是一个客户机证书,采用 base64 二进制编码形式。
安全头部中的第三个项是一个 <ds:Signature> 块,其中包含三个子元素。第一个子元素 <ds:SignedInfo> 是直接进行签名的消息部分。<ds:SignedInfo> 中的第一个子元素标识用于自身标准化和签名的算法。后面是一个 <ds:Reference> 子元素,针对签名中包含的每个消息组件。每个子 <ds:Reference> 元素根据标识符引用一个特定消息组件并提供应用到该组件的标准化和摘要算法,以及生成的摘要值。<ds:SignedInfo> 的其余子元素提供了实际的签名值和一个用于检验签名的公开密匙的引用(在本例中为此前在头部中的 <wsse:BinarySecurityToken> 中包含的证书,由 wsu:Id="CertId-2650016" 标识)。
加密和签名消息
向已签名的消息进行加密非常简单,只需要向策略添加一个 <sp:EncryptedParts> 元素来标识将被加密的组件,以及添加一些额外的 Rampart 配置信息。清单 4 展示了针对这一用途的策略的客户机版本(为了适合页面宽度再次进行了编辑 — 查看示例代码中的 signencr-policy-client.xml 文件获得完整文本),其中在 清单 1 策略的基础上新添的内容以粗体显示:
清单 4. 用于签名和加密(客户机)的 WS-Policy/WS-SecurityPolicy
<!-- Client policy for first signing and then encrypting all messages, with the certificate included in the message from client to server but only a thumbprint on messages from the server to the client. --> <wsp:Policy wsu:Id="SignEncr" xmlns:wsu="http://.../oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"> <wsp:ExactlyOne> <wsp:All> <sp:AsymmetricBinding xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"> <wsp:Policy> <sp:InitiatorToken> <wsp:Policy> <sp:X509Token sp:IncludeToken="http://.../IncludeToken/AlwaysToRecipient"/> </wsp:Policy> </sp:InitiatorToken> <sp:RecipientToken> <wsp:Policy> <sp:X509Token sp:IncludeToken="http://.../IncludeToken/Never"> <wsp:Policy> <sp:RequireThumbprintReference/> </wsp:Policy> </sp:X509Token> </wsp:Policy> </sp:RecipientToken> <sp:AlgorithmSuite> <wsp:Policy> <sp:TripleDesRsa15/> </wsp:Policy> </sp:AlgorithmSuite> <sp:Layout> <wsp:Policy> <sp:Strict/> </wsp:Policy> </sp:Layout> <sp:IncludeTimestamp/> <sp:OnlySignEntireHeadersAndBody/> </wsp:Policy> </sp:AsymmetricBinding> <sp:SignedParts xmlns:sp="http://.../200702"> <sp:Body/> </sp:SignedParts> <sp:EncryptedParts xmlns:sp="http://.../200702"> <sp:Body/> </sp:EncryptedParts> <ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy"> <ramp:user>clientkey</ramp:user> <ramp:encryptionUser>serverkey</ramp:encryptionUser> <ramp:passwordCallbackClass >com.sosnoski.ws.library.adb.PWCBHandler</ramp:passwordCallbackClass> <ramp:signatureCrypto> <ramp:crypto provider="org.apache.ws.security.components.crypto.Merlin"> <ramp:property name="org.apache.ws.security.crypto.merlin.keystore.type" >JKS</ramp:property> <ramp:property name="org.apache.ws.security.crypto.merlin.file" >client.keystore</ramp:property> <ramp:property name="org.apache.ws.security.crypto.merlin.keystore.password" >nosecret</ramp:property> </ramp:crypto> </ramp:signatureCrypto> <ramp:encryptionCrypto> <ramp:crypto provider="org.apache.ws.security.components.crypto.Merlin"> <ramp:property name="org.apache.ws.security.crypto.merlin.keystore.type" >JKS</ramp:property> <ramp:property name="org.apache.ws.security.crypto.merlin.file" >client.keystore</ramp:property> <ramp:property name="org.apache.ws.security.crypto.merlin.keystore.password" >nosecret</ramp:property> </ramp:crypto> </ramp:encryptionCrypto> </ramp:RampartConfig> </wsp:All> </wsp:ExactlyOne> </wsp:Policy> |
|
使用加密不需要 用到 清单 4 策略中的第一处修改,但这是个好主意。在使用加密时,客户机在发送初始请求时需要用到服务器证书(因为要使用证书中的服务器公开密匙进行加密)。由于客户机需要具有服务器证书,并不表示要将服务器证书发送给客户机。清单 4 策略中经过修改的 <sp:RecipientToken> 反映了这个用例,表示不应发送证书(sp:IncludeToken=".../Never"),而应当使用 thumbprint reference(实际上就是一个证书散列)。thumbprint reference 要比完整的证书更加简洁,因此使用引用可以减小消息的大小和处理开销。
实际实现加密的修改是新添的 <sp:EncryptedParts> 元素。这个元素表示将要使用加密,而内容 <sp:Body> 元素表示需要对消息中的 SOAP 消息体进行加密。
清单 4 中新添的 Rampart 配置信息包含一个 <ramp:encryptionUser> 元素和一个 <ramp:encryptionCrypto> 元素,前者为用于加密信息的公开密匙(即证书)分配一个别名,后者指出如何访问包含证书的 keystore。在示例应用程序中,对用于签名的私有密匙和用于加密的公开密匙使用了相同的 keystore,因此 <ramp:encryptionCrypto> 元素只不过是对现有的 <ramp:signatureCrypto> 元素进行重命名后的副本。
在运行时,Rampart 需要获得用于保护私有密匙的密码,这个私有密匙用于对已加密数据进行解密。前面的密码回调用于获得私有密匙密码(用于实现签名),如 清单 2 所示,还提供了用于解密的密码,因此不需要做任何修改。
运行示例应用程序
要尝试运行使用了签名和加密的示例应用程序,首先需要编辑 build.properties 文件。将客户机策略行修改为 client.policy=signencr-policy-client.xml,将服务器策略修改为 server-policy=signencr-policy-server.xml。随后可以通过运行 ant 重新构建应用程序,将生成的 library-signencr.aar 文件部署到 Axis2 安装中,然后运行 ant run 来进行尝试。
清单 5 显示了依次使用签名和加密后的请求-消息捕捉,与 清单 3 中以粗体显示的服务器版本有着明显的不同:
清单 5. 使用了签名和加密的消息
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"> <soapenv:Header> <wsse:Security xmlns:wsse=".../oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1"> <wsu:Timestamp xmlns:wsu=".../oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-4067003"> <wsu:Created>2009-04-21T23:15:47.701Z</wsu:Created> <wsu:Expires>2009-04-21T23:20:47.701Z</wsu:Expires> </wsu:Timestamp> <xenc:EncryptedKey Id="EncKeyId-urn:uuid:6E12E251E439C034FA12403557497352"> <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/> <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <wsse:SecurityTokenReference> <wsse:KeyIdentifier EncodingType="http://...-wss-soap-message-security-1.0#Base64Binary" ValueType="http://.../oasis-wss-soap-message-security-1.1#ThumbprintSHA1" >uYn3PK2wXheN2lLZr4n2mJjoWE0=</wsse:KeyIdentifier> </wsse:SecurityTokenReference> </ds:KeyInfo> <xenc:CipherData> <xenc:CipherValue>OBUcMI...OIPQEUQaxkZps=</xenc:CipherValue> </xenc:CipherData> <xenc:ReferenceList> <xenc:DataReference URI="#EncDataId-28290629"/> </xenc:ReferenceList> </xenc:EncryptedKey> <wsse:BinarySecurityToken xmlns:wsu="http://.../oasis-200401-wss-wssecurity-utility-1.0.xsd" EncodingType="http://...-wss-soap-message-security-1.0#Base64Binary" ValueType="http://.../oasis-200401-wss-x509-token-profile-1.0#X509v1" wsu:Id="CertId-2650016">MIICo...QUBCPx+m8/0n33w==</wsse:BinarySecurityToken> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="Signature-12818976"> <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 URI="#Id-28290629"> <ds:Transforms> <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>5RQy7La+tL2kyz/ae1Z8Eqw2qiI=</ds:DigestValue> </ds:Reference> <ds:Reference URI="#Timestamp-4067003"> <ds:Transforms> <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>GAt/gC/4mPbnKcfahUW0aWE43Y0=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>DhamMx...+Umrnims=</ds:SignatureValue> <ds:KeyInfo Id="KeyId-31999426"> <wsse:SecurityTokenReference xmlns:wsu=".../oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="STRId-19267322"> <wsse:Reference URI="#CertId-2650016" ValueType=".../oasis-200401-wss-x509-token-profile-1.0#X509v1"/> </wsse:SecurityTokenReference> </ds:KeyInfo> </ds:Signature> </wsse:Security> </soapenv:Header> <soapenv:Body xmlns:wsu=".../oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Id-28290629"> <xenc:EncryptedData Id="EncDataId-28290629" Type="http://www.w3.org/2001/04/xmlenc#Content"> <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/> <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <wsse:SecurityTokenReference xmlns:wsse="http://.../oasis-200401-wss-wssecurity-secext-1.0.xsd"> <wsse:Reference URI="#EncKeyId-urn:uuid:6E12E251E439C034FA12403557497352"/> </wsse:SecurityTokenReference> </ds:KeyInfo> <xenc:CipherData> <xenc:CipherValue>k9IzAEG...3jBmonCsk=</xenc:CipherValue> </xenc:CipherData> </xenc:EncryptedData> </soapenv:Body> </soapenv:Envelope> |