3 Stimmen

WCF 4 - TransportWithMessageCredential mit X.509-Zertifikaten für Transport- und Nachrichtensicherheit

Ich versuche, einen auf IIS gehosteten WCF4-Dienst zu erstellen, der X.509-Zertifikate für die Nachrichtensicherheit und SSL mit der erforderlichen gegenseitigen Authentifizierung für die Transportsicherheit verwendet (die Projektspezifikation erfordert die Verwendung von WS-Security UND SSL, AFAIK nur eine ist normalerweise der Weg zu gehen, aber egal).

Ich habe mein TestRootCA erstellt und damit ein Server-Zertifikat (localhost) und ein Client-Zertifikat (TestUser) ausgestellt. Ich wollte zunächst nur die Transportsicherheit herstellen und testen, also konfigurierte ich IIS für die Verwendung von https, konfigurierte das SSL-Zertifikat (localhost-Zertifikat, das ich erstellt hatte) und konfigurierte IIS für erfordern ein Client-Zertifikat von Kunden. Ich änderte dann Service web.config, machte die entsprechende svcutil.conf und lief svcutil, die erfolgreich Client-Proxy-Klasse und app.config für meine Test-WinForms-Anwendung gemacht. Ich setzte das Zertifikat beim Erstellen von Proxy-Client durch Aufruf:

var client = new ServiceClient();
client.ClientCredentials.ClientCertificate.SetCertificate(System.Security.Cryptography.X509Certificates.StoreLocation.CurrentUser, System.Security.Cryptography.X509Certificates.StoreName.My, System.Security.Cryptography.X509Certificates.X509FindType.FindBySubjectDistinguishedName, "CN=TestUser");
MessageBox.Show(client.GetData(42));

So weit, so gut. Aber wenn ich die web.config des Dienstes ändere, um TrasportWithMessageCredential (anstelle von Transport) zu verwenden und "Certificate" als clientCredentialType für die Nachrichtensicherheit anzugeben, erhalte ich HTTP 403 - The HTTP request was forbidden with client authentication scheme 'Anonymous' obwohl ich "Zertifikat" angegeben habe.

Meine endgültige web.config sieht wie folgt aus:

<system.serviceModel>
    <bindings>
        <wsHttpBinding>
            <binding name="wsHttpEndpointBinding">
                <security mode="TransportWithMessageCredential">
                    <transport clientCredentialType="Certificate"/>
                    <message clientCredentialType="Certificate"/>
                </security>
            </binding>
        </wsHttpBinding>
    </bindings>
    <services>
        <service behaviorConfiguration="serviceBehavior" name="Service">
            <endpoint binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" name="wsHttpEndpoint" contract="IService" />
            <endpoint address="mex" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" name="mexEndpoint" contract="IMetadataExchange" />
        </service>
    </services>
    <behaviors>
        <serviceBehaviors>
            <behavior name="serviceBehavior">
                <serviceMetadata httpsGetEnabled="true" />
                <serviceDebug includeExceptionDetailInFaults="true" />
            </behavior>
        </serviceBehaviors>
    </behaviors>
</system.serviceModel>

und meine client app.conf:

<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="TransportWithMessageCredential">
                    <transport clientCredentialType="Certificate"/>
                    <message clientCredentialType="Certificate"/>
                </security>
            </binding>
        </wsHttpBinding>
    </bindings>
    <client>
        <endpoint address="https://localhost/WCFTestService/Service.svc" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpoint" contract="IService" name="wsHttpEndpoint" />
    </client>
</system.serviceModel>

Irgendwelche Ideen?

EDITAR:

Ich habe es geschafft, es zum Laufen zu bringen, indem ich die IIS SSL-Einstellungen für das Client-Zertifikat von erfordern a akzeptieren . Wenn ich Nachrichtensicherheit mit Zertifikaten über Transportsicherheit mit SSL einführe, scheint es, dass der Client das Zertifikat für die Nachrichtensignierung verwendet, aber pas für die gegenseitige Authentifizierung über SSL (es wird versucht, sich als anonyme obwohl sie ein Zertifikat zugewiesen bekommen hat).

Ich bin mir nicht sicher, warum das passiert, ich hätte gerne einen Kommentar von einem Experten :).

2voto

Boris B. Punkte 4808

Wie in der Frage angegeben, habe ich es zum Laufen gebracht, indem ich die IIS SSL-Einstellungen für Client-Zertifikate von require a accept . Im Diensteingabepunkt prüfe ich dann programmatisch das Zertifikat des entfernten Benutzers (wenn es nicht ungültig ist).

1voto

DkAngelito Punkte 1068

Im Abschnitt "Verhalten" müssen Sie die Zertifikate angeben, die zur Verschlüsselung der Nachricht verwendet werden sollen, da diese sich von denen unterscheiden können, die zur Einrichtung des https-Kanals verwendet werden

würde es auf dem Server folgendermaßen aussehen

<system.serviceModel> 
 <behaviors>     
    <serviceBehaviors>     
        <behavior name="serviceBehavior">
      <serviceCredentials>
        <serviceCertificate findValue="ServerCertificate"
                            storeLocation="CurrentUser"
                            storeName="My"
                            x509FindType="FindByIssuerName" />
        <clientCertificate>
          <certificate findValue ="ClientCertificate"
                       storeLocation="CurrentUser"
                            storeName="My"
                            x509FindType="FindByIssuerName"/>
          <authentication certificateValidationMode ="PeerTrust"/>
        </clientCertificate>
      </serviceCredentials>
            <serviceMetadata httpsGetEnabled="true" />     
            <serviceDebug includeExceptionDetailInFaults="true" />     
        </behavior>     
    </serviceBehaviors>     
</behaviors>   
</system.serviceModel> 

und das Gleiche im Client zu tun, würde das folgendermaßen aussehen

<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="TransportWithMessageCredential">        
                    <transport clientCredentialType="Certificate"/>        
                    <message clientCredentialType="Certificate"/>        
                </security>        
            </binding>        
        </wsHttpBinding>        
    </bindings>
 <behaviors>      
  <endpointBehaviors>        
    <behavior name="ClientCredentialsBehavior">
      <clientCredentials>            
        <clientCertificate x509FindType="FindBySubjectName"
                           findValue="ClientCertificate"
                           storeLocation="CurrentUser"
                           storeName="My"/>
        <serviceCertificate>
          <defaultCertificate x509FindType="FindBySubjectName"
                              findValue="ServerCertificate"
                              storeLocation="CurrentUser"
                              storeName="My"/>
        </serviceCertificate>
      </clientCredentials>
    </behavior>
  </endpointBehaviors>
</behaviors>

    <client>        
        <endpoint address="https://localhost/WCFTestService/Service.svc" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpoint" contract="IService" name="wsHttpEndpoint" behaviorConfiguration="ClientCredentialsBehavior" />        
    </client>        
</system.serviceModel>

Natürlich müssen Sie den richtigen Speicherort und Namen der Zertifikate auf dem Server und dem Client festlegen.

Ich hoffe, das hilft weiter

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X