使用证书签署 WCF 消息
Sign WCF message with certificate
我正在尝试调用第三方服务。我需要用证书签署我的消息。
我使用 SOAPUI 检查了连接,它工作正常。我现在正尝试从 WCF 客户端进行调用,但无法使其正常工作。
我对此不熟悉,可能错过了一个明显的步骤。
svcutil 生成的配置如下所示:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="ServiceBinding">
<security mode="Transport" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://url.com" binding="basicHttpBinding"
bindingConfiguration="ServiceBinding" contract="ServiceContract"
name="Name" />
</client>
</system.serviceModel>
</configuration>
我添加了一个 endpointBehaviour 来从商店获取证书。我还必须更改绑定配置,因为签名没有添加到消息中;我将安全模式更改为 TransportWithMessageCredentials
并将消息的客户端凭据类型设置为 Certificate
。
修改后的配置如下(我去掉了不相关的部分):
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="ServiceBinding">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="Certificate"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://url.com" behaviorConfiguration="Behavior"
binding="basicHttpBinding" bindingConfiguration="ServiceBinding"
contract="ServiceContract" name="Name" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="Behavior">
<clientCredentials>
<clientCertificate storeName="My" x509FindType="FindByThumbprint" findValue="..."/>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
</configuration>
当我尝试拨打电话时,出现以下错误:
Security processor was unable to find a security header in the
message. This might be because the message is an unsecured fault or
because there is a binding mismatch between the communicating parties.
This can occur if the service is configured for security and the
client is not using security.
我找到了一些关于此错误的帖子,但其中 none 可以帮助我。
我添加了 ProtectionLevel=System.Net.Security.ProtectionLevel.Sign
如 this post.
中所示的 ServiceContractAttribute
在此先感谢您提供的任何帮助。
编辑:
检查跟踪日志后,我看到消息已发送并且我收到了有意义的响应。但是,响应中没有 header (我认为这会导致异常)。有没有一种方法可以将我的客户端配置为 不 检查响应中的 header?
请求跟踪:
<?xml version="1.0"?>
<E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent">
<System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system">
<EventID>0</EventID>
<Type>3</Type>
<SubType Name="Information">0</SubType>
<Level>8</Level>
<TimeCreated SystemTime="2015-04-21T09:41:19.9227910Z"/>
<Source Name="System.ServiceModel.MessageLogging"/>
<Correlation ActivityID="{ba5c25df-1f0a-4375-8b15-e2160e21bc14}"/>
<Execution ProcessName="w3wp" ProcessID="8540" ThreadID="16"/>
<Channel/>
<Computer>PC673</Computer>
</System>
<ApplicationData>
<TraceData>
<DataItem>
<MessageLogTraceRecord xmlns="http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace" Time="2015-04-21T11:41:19.9217909+02:00" Source="TransportSend" Type="System.ServiceModel.Security.SecurityAppliedMessage">
<Addressing>
<Action/>
<To>https://url.com</To>
</Addressing>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header>
<o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
<u:Timestamp u:Id="_0">
<u:Created>2015-04-21T09:41:08.287Z</u:Created>
<u:Expires>2015-04-21T09:46:08.287Z</u:Expires>
</u:Timestamp>
<o:BinarySecurityToken>
<!-- Removed-->
</o:BinarySecurityToken>
<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#rsa-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>zvttNRawVVcleH5WAYMCi7oBzpM=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>iEMTR/xKruW1TeqJiPdXjNKG3D4ZWyfFM3T+iPy8NSCpwQIpwXmsmrOjT2N5QJoG7S+wyIm2Vsa4rmlmyYBM18rNMeN+luHuUYvNh9ammWyYgam5/mpGBmR8KJiyPSiCxCPeUWuL8z5ag2wGtTrTH/JqOsHfdobnhznvQJgPAc8YWAk6On7SkHT+nKikGv1rEfbCtOBeggbBLLzSArVOBDDOZhWRpRJLhvU6XhlYj1IbgMy4tFP8f0+SESU/UQM+0bBnt0IDwwtTQIyeheifVJINeUHe+T1Pr8qYtyo9/sLulr1vkFe0DAokv1R1WRCU5IoE38I/ptILOMvIq1s3OQ==</SignatureValue>
<KeyInfo>
<o:SecurityTokenReference>
<o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-bda377d4-237a-46b7-a7c3-b7d47578c278-1"/>
</o:SecurityTokenReference>
</KeyInfo>
</Signature>
</o:Security>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- Valid request -->
</s:Body>
</s:Envelope>
</MessageLogTraceRecord>
</DataItem>
</TraceData>
</ApplicationData>
</E2ETraceEvent>
响应轨迹:
<?xml version="1.0"?>
<E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent">
<System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system">
<EventID>0</EventID>
<Type>3</Type>
<SubType Name="Information">0</SubType>
<Level>8</Level>
<TimeCreated SystemTime="2015-04-21T09:41:22.4049329Z"/>
<Source Name="System.ServiceModel.MessageLogging"/>
<Correlation ActivityID="{ba5c25df-1f0a-4375-8b15-e2160e21bc14}"/>
<Execution ProcessName="w3wp" ProcessID="8540" ThreadID="16"/>
<Channel/>
<Computer>PC673</Computer>
</System>
<ApplicationData>
<TraceData>
<DataItem>
<MessageLogTraceRecord xmlns="http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace" Time="2015-04-21T11:41:22.4049329+02:00" Source="TransportReceive" Type="System.ServiceModel.Channels.BufferedMessage">
<HttpResponse>
<StatusCode>OK</StatusCode>
<StatusDescription>OK</StatusDescription>
<WebHeaders>
<X-Backside-Transport>OK OK</X-Backside-Transport>
<Connection>Keep-Alive</Connection>
<Transfer-Encoding>chunked</Transfer-Encoding>
<X-Client-IP>194.78.45.187</X-Client-IP>
<Content-Type>text/xml</Content-Type>
<Date>Tue, 21 Apr 2015 09:41:11 GMT</Date>
<Server>Apache-Coyote/1.1</Server>
</WebHeaders>
</HttpResponse>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"/>
<Body>
<!-- Meaningful response - the same I get when using SOAPUI -->
</Body>
</Envelope>
</MessageLogTraceRecord>
</DataItem>
</TraceData>
</ApplicationData>
</E2ETraceEvent>
wcf 中的绑定在客户端和服务器端必须相同。如果将安全模式设置为传输,则消息本身不会被加密。它只是一个安全隧道。
所以设置securitymode为message,protectionlevel为encrypt and sign.
下面是对加密选项的一个很好的概述:
https://msdn.microsoft.com/en-us/library/ff650862.aspx
我通过创建自定义绑定解决了这个问题。
<binding name="ServiceBinding">
<security authenticationMode="CertificateOverTransport"
messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
requireDerivedKeys="false"
securityHeaderLayout="Lax"
enableUnsecuredResponse="true" />
<textMessageEncoding messageVersion="Soap11" />
<httpsTransport />
</binding>
这里的关键是enableUnsecuredResponse="true"
。这样,我可以在不崩溃的情况下接收未签名的响应。
我正在尝试调用第三方服务。我需要用证书签署我的消息。
我使用 SOAPUI 检查了连接,它工作正常。我现在正尝试从 WCF 客户端进行调用,但无法使其正常工作。 我对此不熟悉,可能错过了一个明显的步骤。
svcutil 生成的配置如下所示:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="ServiceBinding">
<security mode="Transport" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://url.com" binding="basicHttpBinding"
bindingConfiguration="ServiceBinding" contract="ServiceContract"
name="Name" />
</client>
</system.serviceModel>
</configuration>
我添加了一个 endpointBehaviour 来从商店获取证书。我还必须更改绑定配置,因为签名没有添加到消息中;我将安全模式更改为 TransportWithMessageCredentials
并将消息的客户端凭据类型设置为 Certificate
。
修改后的配置如下(我去掉了不相关的部分):
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="ServiceBinding">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="Certificate"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://url.com" behaviorConfiguration="Behavior"
binding="basicHttpBinding" bindingConfiguration="ServiceBinding"
contract="ServiceContract" name="Name" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="Behavior">
<clientCredentials>
<clientCertificate storeName="My" x509FindType="FindByThumbprint" findValue="..."/>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
</configuration>
当我尝试拨打电话时,出现以下错误:
Security processor was unable to find a security header in the message. This might be because the message is an unsecured fault or because there is a binding mismatch between the communicating parties. This can occur if the service is configured for security and the client is not using security.
我找到了一些关于此错误的帖子,但其中 none 可以帮助我。
我添加了 ProtectionLevel=System.Net.Security.ProtectionLevel.Sign
如 this post.
在此先感谢您提供的任何帮助。
编辑:
检查跟踪日志后,我看到消息已发送并且我收到了有意义的响应。但是,响应中没有 header (我认为这会导致异常)。有没有一种方法可以将我的客户端配置为 不 检查响应中的 header?
请求跟踪:
<?xml version="1.0"?>
<E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent">
<System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system">
<EventID>0</EventID>
<Type>3</Type>
<SubType Name="Information">0</SubType>
<Level>8</Level>
<TimeCreated SystemTime="2015-04-21T09:41:19.9227910Z"/>
<Source Name="System.ServiceModel.MessageLogging"/>
<Correlation ActivityID="{ba5c25df-1f0a-4375-8b15-e2160e21bc14}"/>
<Execution ProcessName="w3wp" ProcessID="8540" ThreadID="16"/>
<Channel/>
<Computer>PC673</Computer>
</System>
<ApplicationData>
<TraceData>
<DataItem>
<MessageLogTraceRecord xmlns="http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace" Time="2015-04-21T11:41:19.9217909+02:00" Source="TransportSend" Type="System.ServiceModel.Security.SecurityAppliedMessage">
<Addressing>
<Action/>
<To>https://url.com</To>
</Addressing>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header>
<o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
<u:Timestamp u:Id="_0">
<u:Created>2015-04-21T09:41:08.287Z</u:Created>
<u:Expires>2015-04-21T09:46:08.287Z</u:Expires>
</u:Timestamp>
<o:BinarySecurityToken>
<!-- Removed-->
</o:BinarySecurityToken>
<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#rsa-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>zvttNRawVVcleH5WAYMCi7oBzpM=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>iEMTR/xKruW1TeqJiPdXjNKG3D4ZWyfFM3T+iPy8NSCpwQIpwXmsmrOjT2N5QJoG7S+wyIm2Vsa4rmlmyYBM18rNMeN+luHuUYvNh9ammWyYgam5/mpGBmR8KJiyPSiCxCPeUWuL8z5ag2wGtTrTH/JqOsHfdobnhznvQJgPAc8YWAk6On7SkHT+nKikGv1rEfbCtOBeggbBLLzSArVOBDDOZhWRpRJLhvU6XhlYj1IbgMy4tFP8f0+SESU/UQM+0bBnt0IDwwtTQIyeheifVJINeUHe+T1Pr8qYtyo9/sLulr1vkFe0DAokv1R1WRCU5IoE38I/ptILOMvIq1s3OQ==</SignatureValue>
<KeyInfo>
<o:SecurityTokenReference>
<o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-bda377d4-237a-46b7-a7c3-b7d47578c278-1"/>
</o:SecurityTokenReference>
</KeyInfo>
</Signature>
</o:Security>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- Valid request -->
</s:Body>
</s:Envelope>
</MessageLogTraceRecord>
</DataItem>
</TraceData>
</ApplicationData>
</E2ETraceEvent>
响应轨迹:
<?xml version="1.0"?>
<E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent">
<System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system">
<EventID>0</EventID>
<Type>3</Type>
<SubType Name="Information">0</SubType>
<Level>8</Level>
<TimeCreated SystemTime="2015-04-21T09:41:22.4049329Z"/>
<Source Name="System.ServiceModel.MessageLogging"/>
<Correlation ActivityID="{ba5c25df-1f0a-4375-8b15-e2160e21bc14}"/>
<Execution ProcessName="w3wp" ProcessID="8540" ThreadID="16"/>
<Channel/>
<Computer>PC673</Computer>
</System>
<ApplicationData>
<TraceData>
<DataItem>
<MessageLogTraceRecord xmlns="http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace" Time="2015-04-21T11:41:22.4049329+02:00" Source="TransportReceive" Type="System.ServiceModel.Channels.BufferedMessage">
<HttpResponse>
<StatusCode>OK</StatusCode>
<StatusDescription>OK</StatusDescription>
<WebHeaders>
<X-Backside-Transport>OK OK</X-Backside-Transport>
<Connection>Keep-Alive</Connection>
<Transfer-Encoding>chunked</Transfer-Encoding>
<X-Client-IP>194.78.45.187</X-Client-IP>
<Content-Type>text/xml</Content-Type>
<Date>Tue, 21 Apr 2015 09:41:11 GMT</Date>
<Server>Apache-Coyote/1.1</Server>
</WebHeaders>
</HttpResponse>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"/>
<Body>
<!-- Meaningful response - the same I get when using SOAPUI -->
</Body>
</Envelope>
</MessageLogTraceRecord>
</DataItem>
</TraceData>
</ApplicationData>
</E2ETraceEvent>
wcf 中的绑定在客户端和服务器端必须相同。如果将安全模式设置为传输,则消息本身不会被加密。它只是一个安全隧道。 所以设置securitymode为message,protectionlevel为encrypt and sign.
下面是对加密选项的一个很好的概述: https://msdn.microsoft.com/en-us/library/ff650862.aspx
我通过创建自定义绑定解决了这个问题。
<binding name="ServiceBinding">
<security authenticationMode="CertificateOverTransport"
messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
requireDerivedKeys="false"
securityHeaderLayout="Lax"
enableUnsecuredResponse="true" />
<textMessageEncoding messageVersion="Soap11" />
<httpsTransport />
</binding>
这里的关键是enableUnsecuredResponse="true"
。这样,我可以在不崩溃的情况下接收未签名的响应。