2010-12-04 151 views
9

过去一周我一直在为这个被诅咒的WCF服务配置而苦苦挣扎,而且我开始怀疑我试图做的事情是不可能的,尽管有文件。通过HTTPS客户端证书验证WCF请求

很简单,我想要一个WCF服务需要一个客户端证书(服务器将在其证书存储区中),然后使用System.ServiceModel.ServiceSecurityContext访问该标识。此外,这需要使用运输安全。

这里是我的服务器配置:

<system.serviceModel> 
    <services> 
     <service behaviorConfiguration="requireCertificate" name="Server.CXPClient"> 
     <endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" name="wsHttpEndpoint" contract="PartnerComm.ContentXpert.Server.ICXPClient" /> 
     <endpoint address="mex" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" name="mexEndpoint" contract="IMetadataExchange" /> 
     <host> 
      <baseAddresses> 
      <add baseAddress="https://localhost:8371/Design_Time_Addresses/Server/CXPClient/" /> 
      </baseAddresses> 
     </host> 
     </service> 
    </services> 
    <behaviors> 
     <serviceBehaviors> 
     <behavior name="requireCertificate"> 
      <serviceMetadata httpsGetEnabled="true" /> 
      <serviceCredentials> 
      <serviceCertificate findValue="CyberdyneIndustries" storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName"/> 
      <clientCertificate> 
       <authentication certificateValidationMode="ChainTrust" trustedStoreLocation="LocalMachine" /> 
      </clientCertificate> 
      </serviceCredentials> 
     </behavior> 
     </serviceBehaviors> 
    </behaviors> 
    <bindings> 
     <wsHttpBinding> 
     <binding name="wsHttpEndpointBinding" maxBufferPoolSize="5242880" maxReceivedMessageSize="5242880"> 
      <readerQuotas maxDepth="32" maxStringContentLength="5242880" maxArrayLength="1073741824" maxBytesPerRead="4096" maxNameTableCharCount="16384" /> 
      <security mode="Transport"> 
      <transport clientCredentialType="Certificate" /> 
      </security> 
     </binding> 
     </wsHttpBinding> 
    </bindings> 
    </system.serviceModel> 

这里是我的客户端配置:

<system.serviceModel> 
    <bindings> 
     <wsHttpBinding> 
     <binding name="wsHttpEndpoint" closeTimeout="00:01:00" openTimeout="00:01:00" 
      receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" 
      transactionFlow="false" hostNameComparisonMode="StrongWildcard" 
      maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" 
      textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false"> 
      <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" 
      maxBytesPerRead="4096" maxNameTableCharCount="16384" /> 
      <reliableSession ordered="true" inactivityTimeout="00:10:00" 
      enabled="false" /> 
      <security mode="Transport"> 
      <transport clientCredentialType="Certificate" /> 
      </security> 
     </binding> 
     </wsHttpBinding> 
    </bindings> 
    <client> 
     <endpoint address="https://localhost:8371/Design_Time_Addresses/Server/CXPClient/" 
     binding="wsHttpBinding" bindingConfiguration="wsHttpEndpoint" behaviorConfiguration="ClientCertificateBehavior" 
     contract="ContentXPertServer.ICXPClient" name="wsHttpEndpoint" /> 
    </client> 
    <behaviors> 
     <endpointBehaviors> 
     <behavior name="ClientCertificateBehavior"> 
      <clientCredentials> 
      <clientCertificate x509FindType="FindBySubjectName" findValue="CyberdyneIndustries" storeLocation="LocalMachine" storeName="TrustedPeople" /> 
      </clientCredentials> 
     </behavior> 
     </endpointBehaviors> 
    </behaviors> 
    </system.serviceModel> 

代码中所有工作完全在安全模式=“无”通过HTTP,当然,也没有认证,而在System.ServiceModel.ServiceSecurityContext中什么都没有。我已经在所有这些元素上尝试了数十种变体,并且所有这些都不可避免地导致请求抛出异常“现有连接被远程主机强行关闭”。

我正在使用自签名证书“​​Cyber​​dyneIndustries”,其CA证书已添加到受信任的CA商店。当我查看证书时,证书会被检出。我经历了http命名空间管理的难题,并解决了这些问题。它看起来像WCF并不真的支持这...请告诉我我错了。

TIA。

回答

2

最终,我决定尝试一下消息安全性,看看这是否会对情况有所了解 - 它的确如此,我将减少我的损失并继续这样做。所以,对此没有明确的答案。

然而,实现消息安全确实暴露了BIG问题,这可能是传输安全问题的根源。有一个从MSDN一块毒药文档:

http://msdn.microsoft.com/en-us/library/ff650751.aspx

在这个页面上,以创建自签名证书的命令如下:

makecert -sk MyKeyName -IV RootCaClientTest .pvk -n “CN = tempClientcert” -IC RootCaClientTest.cer -sr currentuser -ss我-sky签名-pe

参数“签名”应改为“交换”。一旦我重新生成了所有证书,邮件安全就开始工作。从这一点来看,最重要的一点是,如果你想实现传输安全,首先要保证消息安全,因为从系统获得的错误消息更具描述性。

0

WsHttpBinding DOES支持传输安全的证书认证。

可以有几件事情错了:

  1. 你加证书来你的店? Cyber​​dyneIndustries以及您曾用于签署的CA? CA应该位于“受信任的根证书颁发机构”

  2. 此外,我已经完成了这种自托管,从来没有在Visual Studio Dev服务器中。尝试至少在IIS中托管您的服务。我不确定VS Dev服务器是否支持证书。

  3. 尝试关闭服务认证。所以客户端不必认证服务。我不知道,如果你想这个应用程式或没有,但只是为了测试,所以我们可以排除这一可能性

    <behavior name="ClientCertificateBehavior"> 
    <clientCredentials> 
        <clientCertificate x509FindType="FindBySubjectName" findValue="CyberdyneIndustries" storeLocation="LocalMachine" storeName="TrustedPeople" /> 
        <serviceCertificate> 
         <authentication certificateValidationMode="None"/> 
        </serviceCertificate> 
    </clientCredentials> 
    

1

是否SSL握手成功吗?启用S​​Channel日志记录以对SSL层进行故障排除。看到这个旧的知识库文章:How to enable Schannel event logging in IIS。虽然是W2K和XP的KB,但启用SChannel日志的步骤相同,并且在较新的系统上仍然有效。启用日志记录后,您将能够确定SSL为什么拒绝该证书。

1

我知道这是3岁,但对于那些谁可能仍然有兴趣...

我在学习WCF(除其他事项外安全)的过程中,能够得到的东西正常工作与netTcpBinding(大概这也适用于WsHttpBindings),使用TransportCredentialType =“Certificate”(和,protectionLevel =“EncryptAndSign”,虽然这与问题没有密切关系)的传输安全模式。

我确实遇到了来自服务器端的强制连接关闭错误,但发现我错过了一个配置。现在都在工作。

这里是我的服务器端配置:

<configuration> 
    <system.serviceModel> 
    <services> 
     <service name="MyNamespace.MyService" behaviorConfiguration="MyServiceBehavior"> 
     <endpoint address="net.tcp://localhost:9002/MyServer" binding="netTcpBinding" bindingConfiguration="TcpCertSecurity" contract="MyNamespace.IMyService" /> 
     </service> 
    </services> 
    <behaviors> 
     <serviceBehaviors> 
     <behavior name="MyServiceBehavior"> 
      <serviceCredentials> 
      <serviceCertificate findValue="MyServiceCert" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" /> 
      <clientCertificate> 
       <authentication certificateValidationMode="PeerTrust"/> 
      </clientCertificate> 
      </serviceCredentials> 
     </behavior> 
     </serviceBehaviors> 
    </behaviors> 
    <bindings> 
     <netTcpBinding> 
     <binding name="TcpCertSecurity"> 
      <security mode="Transport"> 
      <transport clientCredentialType="Certificate" protectionLevel="EncryptAndSign" /> 
      </security> 
     </binding> 
     </netTcpBinding> 
    </bindings> 
    </system.serviceModel> 
</configuration> 

而我的客户端配置:

<configuration> 
    <system.serviceModel> 
    <client> 
     <endpoint address="net.tcp://localhost:9002/MyServer" binding="netTcpBinding" 
      bindingConfiguration="TcpCertSecurity" contract="MyNamespace.IMyService" 
      behaviorConfiguration="MyServiceBehavior"> 
     <identity> 
      <dns value="MyServiceCert" /> 
     </identity> 
     </endpoint> 
    </client> 
    <bindings> 
     <netTcpBinding> 
     <binding name="TcpCertSecurity"> 
      <security mode="Transport"> 
      <transport clientCredentialType="Certificate" protectionLevel="EncryptAndSign" /> 
      </security> 
     </binding> 
     </netTcpBinding> 
    </bindings> 
    <behaviors> 
     <endpointBehaviors> 
     <behavior name="MyServiceBehavior"> 
      <clientCredentials> 
      <serviceCertificate> 
       <authentication certificateValidationMode="PeerTrust" /> 
      </serviceCertificate> 
      <clientCertificate findValue="MyServiceCert" storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName" /> 
      </clientCredentials> 
     </behavior> 
     </endpointBehaviors> 
    </behaviors> 
    </system.serviceModel> 
</configuration> 

我创建了一个证书链的服务器(自签名的受信任的根证书+证书使用描述here描述的技术,并将Root证书和子证书存储在我的服务器主机的证书存储中。最后,我将该服务器证书+公钥导入到我的客户主机(位于LocalMachine/TrustedPeople)中的证书存储中。