Freigeben über


X.509-Zertifikats-Validierungssteuerelement

In diesem Beispiel wird veranschaulicht, wie ein benutzerdefiniertes X.509-Zertifikats-Validierungssteuerelement implementiert wird. Dies ist nützlich, wenn keines der integrierten X.509-Zertifikats-Prüfungsmodi den Anforderungen der Anwendung entspricht. Dieses Beispiel zeigt einen Dienst, der über ein benutzerdefiniertes Validierungssteuerelement verfügt, das selbst herausgegebene Zertifikate akzeptiert. Der Client verwendet solch ein Zertifikat, um den Dienst zu authentifizieren.

Hinweis: Da jeder ein selbst herausgegebenes Zertifikat erstellen kann, ist das vom Dienst verwendete benutzerdefinierte Validierungssteuerelement unsicherer als das Standardverhalten vom ChainTrust X509CertificateValidationMode. Die daraus resultierenden Sicherheitsauswirkungen sollten sorgfältig bedacht werden, bevor diese Validierungslogik im Produktionscode verwendet wird.

Insgesamt zeigt dieses Beispiel Folgendes:

  • Der Client kann mit einem X.509-Zertifikat authentifiziert werden.
  • Der Server überprüft die Clientanmeldeinformationen mithilfe eines benutzerdefinierten X509CertificateValidator.
  • Der Server wird mit dem X.509-Zertifikat des Servers authentifiziert.

Der Dienst macht einen einzelnen Endpunkt zur Kommunikation mit dem Dienst verfügbar, der mit der Konfigurationsdatei "App.conf" definiert wird. Der Endpunkt besteht aus einer Adresse, einer Bindung und einem Vertrag. Die Bindung wird mit einer normalen wsHttpBinding konfiguriert, die standardmäßig WSSecurity und Clientzertifikatauthentifizierung verwendet. Das Dienstverhalten gibt den benutzerdefinierten Modus zur Prüfung von X.509-Clientzertifikaten zusammen mit dem Typ der Validierungssteuerelementklasse an. Das Verhalten gibt auch das Serverzertifikat mit dem serviceCertificate-Element an. Das Serverzertifikat muss für den SubjectName denselben Wert wie das findValue in dem serviceCertificate element of serviceCredentials enthalten.

  <system.serviceModel>
    <services>
      <service name="Microsoft.ServiceModel.Samples.CalculatorService"
               behaviorConfiguration="CalculatorServiceBehavior">
        <!-- use host/baseAddresses to configure base address -->
        <!-- provided by host -->
        <host>
          <baseAddresses>
            <add baseAddress =
                "https://localhost:8001/servicemodelsamples/service" />
          </baseAddresses>
        </host>
        <!-- use base address specified above, provide one endpoint -->
        <endpoint address="certificate"
               binding="wsHttpBinding"
               bindingConfiguration="Binding" 
               contract="Microsoft.ServiceModel.Samples.ICalculator" />
      </service>
    </services>
    <bindings>
      <wsHttpBinding>
        <!-- X509 certificate binding -->
        <binding name="Binding">
          <security mode="Message">
            <message clientCredentialType="Certificate" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="CalculatorServiceBehavior">
          <serviceDebug includeExceptionDetailInFaults ="true"/>
          <serviceCredentials>
            <!--The serviceCredentials behavior allows one -->
            <!-- to specify authentication constraints on -->
            <!-- client certificates. -->
            <clientCertificate>
              <!-- Setting the certificateValidationMode to -->
              <!-- Custom means that if the custom -->
              <!-- X509CertificateValidator does NOT throw -->
              <!-- an exception, then the provided certificate -- >
              <!-- will be trusted without performing any -->
              <!-- validation beyond that performed by the custom-->
              <!-- validator. The security implications of this -->
              <!-- setting should be carefully considered before -->
              <!-- using Custom in production code. -->
              <authentication 
                 certificateValidationMode="Custom" 
                 customCertificateValidatorType =
"Microsoft.ServiceModel.Samples.CustomX509CertificateValidator, service" />
            </clientCertificate>
            <!-- The serviceCredentials behavior allows one to -- >
            <!--define a service certificate. -->
            <!--A service certificate is used by a client to  -->
            <!--authenticate the service and provide message  -->
            <!--protection. This configuration references the  -->
            <!--"localhost" certificate installed during the setup  -->
            <!--instructions. -->
            <serviceCertificate findValue="localhost" 
                 storeLocation="LocalMachine" 
                 storeName="My" x509FindType="FindBySubjectName" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
      </system.serviceModel>

Die Clientendpunktkonfiguration besteht aus einem Konfigurationsnamen, einer absoluten Adresse für den Dienstendpunkt, der Bindung und dem Vertrag. Die Clientbindung wird mit dem entsprechenden Modus und der clientCredentialType-Nachricht konfiguriert.

<system.serviceModel>
    <client>
      <!-- X509 certificate based endpoint -->
      <endpoint name="Certificate"
        address=
        "https://localhost:8001/servicemodelsamples/service/certificate" 
                binding="wsHttpBinding" 
                bindingConfiguration="Binding" 
                behaviorConfiguration="ClientCertificateBehavior"
                contract="Microsoft.ServiceModel.Samples.ICalculator">
      </endpoint>
    </client>
    <bindings>
        <wsHttpBinding>
            <!-- X509 certificate binding -->
            <binding name="Binding">
                <security mode="Message">
                    <message clientCredentialType="Certificate" />
               </security>
            </binding>
       </wsHttpBinding>
    </bindings>
    <behaviors>
      <endpointBehaviors>
        <behavior name="ClientCertificateBehavior">
          <clientCredentials>
            <serviceCertificate>
              <!-- Setting the certificateValidationMode to -->
              <!-- PeerOrChainTrust means that if the certificate -->
              <!-- is in the user's Trusted People store, then it -->
              <!-- is trusted without performing a validation of -->
              <!-- the certificate's issuer chain. -->
              <!-- This setting is used here for convenience so -->
              <!-- that the sample can be run without having to -->
              <!-- have certificates issued by a certification -->
              <!-- authority (CA). This setting is less secure -->
              <!-- than the default, ChainTrust. The security -->
              <!-- implications of this setting should be -->
              <!-- carefully considered before using -->
              <!-- PeerOrChainTrust in production code.-->
              <authentication 
                  certificateValidationMode="PeerOrChainTrust" />
            </serviceCertificate>
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>

Die Clientimplementierung legt das zu verwendende Clientzertifikat fest.

// Create a client with Certificate endpoint configuration
CalculatorClient client = new CalculatorClient("Certificate");
try
{
    client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySubjectName, "test1");

    // Call the Add service operation.
    double value1 = 100.00D;
    double value2 = 15.99D;
    double result = client.Add(value1, value2);
    Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);

    // Call the Subtract service operation.
    value1 = 145.00D;
    value2 = 76.54D;
    result = client.Subtract(value1, value2);
    Console.WriteLine("Subtract({0},{1}) = {2}", value1, value2, result);

    // Call the Multiply service operation.
    value1 = 9.00D;
    value2 = 81.25D;
    result = client.Multiply(value1, value2);
    Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);

    // Call the Divide service operation.
    value1 = 22.00D;
    value2 = 7.00D;
    result = client.Divide(value1, value2);
    Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);
    client.Close();
}
catch (TimeoutException e)
{
    Console.WriteLine("Call timed out : {0}", e.Message);
    client.Abort();
}
catch (CommunicationException e)
{
    Console.WriteLine("Call failed : {0}", e.Message);
    client.Abort();
}
catch (Exception e)
{
    Console.WriteLine("Call failed : {0}", e.Message);
    client.Abort();
}

In diesem Beispiel wird ein benutzerdefinierter X509CertificateValidator verwendet, um Zertifikate zu überprüfen. Das Beispiel implementiert CustomX509CertificateValidator, das von X509CertificateValidator abgeleitet ist. Weitere Informationen finden Sie in der Dokumentation zu X509CertificateValidator. In diesem speziellen Beispiel zu einem benutzerdefinierten Validierungssteuerelement ist die Validate-Methode so implementiert, dass sie jedes selbst herausgegebene X.509-Zertifikat akzeptiert, wie im folgenden Code gezeigt.

public class CustomX509CertificateValidator : X509CertificateValidator
{
  public override void Validate ( X509Certificate2 certificate )
  {
   // Only accept self-issued certificates
   if (certificate.Subject != certificate.Issuer)
     throw new Exception("Certificate is not self-issued");
   }
}

Nachdem das Validierungssteuerelement im Dienstcode implementiert ist, muss der Diensthost über die zu verwendende Validierungssteuerelementinstanz informiert werden. Dies wird mit dem folgenden Code durchgeführt.

serviceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.Custom;
serviceHost.Credentials.ClientCertificate.Authentication.CustomCertificateValidator = new CustomX509CertificateValidator();

Sie können dasselbe aber auch wie folgt in der Konfiguration vornehmen.

<behaviors>
    <serviceBehaviors>
     <behavior name="CalculatorServiceBehavior">
       ...
   <serviceCredentials>
    <!--The serviceCredentials behavior allows one to specify --> 
    <!--authentication constraints on client certificates.-->
    <clientCertificate>
    <!-- Setting the certificateValidationMode to Custom means --> 
    <!--that if the custom X509CertificateValidator does NOT --> 
    <!--throw an exception, then the provided certificate will-- > 
    <!-- be trusted without performing any validation beyond that-- >
    <!-- performed by the custom validator. The security -- > 
    <!--implications of this setting should be carefully -- >
    <!--considered before using Custom in production code. -->
    <authentication certificateValidationMode="Custom"
       customCertificateValidatorType =
"Microsoft.ServiceModel.Samples. CustomX509CertificateValidator, service" />
   </clientCertificate>
   ...
  </behavior>
 </serviceBehaviors>
</behaviors>

Wenn Sie das Beispiel ausführen, werden die Anforderungen und Antworten für den Vorgang im Clientkonsolenfenster angezeigt. Der Client sollte alle Methoden erfolgreich aufrufen. Drücken Sie im Clientfenster die EINGABETASTE, um den Client zu schließen.

Setupbatchdatei

Mit der in diesem Beispiel enthaltenen Setup.bat-Batchdatei können Sie den Server mit relevanten Zertifikaten zum Ausführen einer selbst gehosteten Anwendung konfigurieren, die serverzertifikatbasierte Sicherheit erfordert. Diese Batchdatei muss geändert werden, um computerübergreifend oder in einem nicht gehosteten Fall zu arbeiten.

Nachfolgend erhalten Sie einen kurzen Überblick über die verschiedenen Abschnitte der Batchdateien, damit Sie sie so ändern können, dass sie in der entsprechenden Konfiguration ausgeführt werden:

  • Erstellen des Serverzertifikats
    Die folgenden Zeilen aus der Setup.bat-Batchdatei erstellen das zu verwendende Serverzertifikat. Die Variable %SERVER_NAME% gibt den Servernamen an. Ändern Sie diese Variable, um einen eigenen Servernamen anzugeben. Der Standardwert ist "localhost".

    echo ************
    echo Server cert setup starting
    echo %SERVER_NAME%
    echo ************
    echo making server cert
    echo ************
    makecert.exe -sr LocalMachine -ss MY -a sha1 -n CN=%SERVER_NAME% -sky exchange -pe
    
  • Installieren des Serverzertifikats in den Clientspeicher für vertrauenswürdige Zertifikate:
    Die folgenden Zeilen in der Setup.bat-Batchdatei kopieren das Serverzertifikat in den Clientspeicher für vertrauenswürdige Personen. Dieser Schritt ist erforderlich, da von Makecert.exe generierten Zertifikaten nicht implizit vom Clientsystem vertraut wird. Wenn Sie bereits über ein Zertifikat verfügen, das von einem vertrauenswürdigen Clientstammzertifikat abstammt (z. B. ein von Microsoft ausgegebenes Zertifikat), ist dieser Schritt zum Auffüllen des Clientzertifikatspeichers mit dem Serverzertifikat nicht erforderlich.

    certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r CurrentUser -s TrustedPeople
    
  • Erstellen des Clientzertifikats
    Die folgenden Zeilen aus der Setup.bat-Batchdatei erstellen das zu verwendende Clientzertifikat. Die Variable % USER_NAME% gibt den Clientnamen an. Dieser Wert wird auf "test1" festgelegt, da dies der Name ist, nach dem der Clientcode sucht. Wenn Sie den Wert von %USER_NAME% ändern, müssen Sie auch den zugehörigen Wert in der Client.cs-Quelldatei ändern und den Client neu erstellen.
    Das Zertifikat wird im persönlichen Speicher unterhalb von CurrentUser gespeichert.

    echo ************
    echo Client cert setup starting
    echo %USER_NAME%
    echo ************
    echo making client cert
    echo ************
    makecert.exe -sr CurrentUser -ss MY -a sha1 -n CN=%USER_NAME% -sky exchange -pe
    
  • Installieren des Clientzertifikats in den Serverspeicher für vertrauenswürdige Zertifikate:
    Die folgenden Zeilen in der Setup.bat-Batchdatei kopieren das Clientzertifikat in den Speicher für vertrauenswürdige Personen. Dieser Schritt ist erforderlich, da von "Makecert.exe" generierten Zertifikaten nicht implizit vom Serversystem vertraut wird. Wenn Sie bereits über ein Zertifikat verfügen, das von einem vertrauenswürdigen Stammzertifikat abstammt (z. B. ein von Microsoft ausgegebenes Zertifikat), ist dieser Schritt zum Auffüllen des Serverzertifikatspeichers mit dem Clientzertifikat nicht erforderlich.

    certmgr.exe -add -r CurrentUser -s My -c -n %USER_NAME% -r LocalMachine -s TrustedPeople
    

So richten Sie das Beispiel ein und erstellen es

  1. Folgen Sie zum Erstellen der Projektmappe den Anweisungen unter Erstellen der Windows Communication Foundation-Beispiele.

  2. Wenn Sie das Beispiel in einer Konfiguration mit einem einzigen Computer oder computerübergreifend ausführen möchten, folgen Sie den folgenden Anweisungen.

So führen Sie das Beispiel auf demselben Computer aus

  1. Stellen Sie sicher, dass der Pfad den Ordner enthält, in dem sich Makecert.exe befindet.

  2. Führen Sie Setup.bat aus dem Beispielinstallationsordner aus. Dadurch werden alle Zertifikate, die zum Ausführen des Beispiels erforderlich sind, installiert.

  3. Starten Sie Service.exe aus dem Ordner service\bin.

  4. Starten Sie Client.exe aus dem Ordner \client\bin. In der Clientkonsolenanwendung wird Clientaktivität angezeigt.

  5. Wenn der Client und der Dienst nicht miteinander kommunizieren können, finden Sie weitere Informationen unter Hinweise zur Fehlerbehebung.

So führen Sie das Beispiel computerübergreifend aus

  1. Erstellen Sie auf dem Dienstcomputer ein Verzeichnis.

  2. Kopieren Sie die Dienstprogrammdateien aus "\service\bin" in das virtuelle Verzeichnis auf dem Dienstcomputer. Kopieren Sie außerdem die Dateien "Setup.bat", "Cleanup.bat", "GetComputerName.vbs" und "ImportClientCert.bat" auf den Dienstcomputer.

  3. Erstellen Sie auf dem Clientcomputer ein Verzeichnis für die Clientbinärdateien.

  4. Kopieren Sie die Clientprogrammdateien in das Clientverzeichnis auf dem Clientcomputer. Kopieren Sie außerdem die Dateien "Setup.bat", "Cleanup.bat" und "ImportServiceCert.bat" auf den Client.

  5. Führen Sie auf dem Server setup.bat service aus. Durch Ausführen von setup.bat mit dem Argument service wird ein Dienstzertifikat mit dem vollqualifizierten Domänennamen des Computers erstellt und das Dienstzertifikat in eine Datei namens "Service.cer" exportiert.

  6. Bearbeiten Sie Service.exe.config so, dass sie den neuen Zertifikatnamen (im findValue-Attribut im serviceCertificate element of serviceCredentials) enthält, der derselbe wie der vollqualifizierte Domänenname des Computers ist. Ändern Sie auch den Computernamen im Element <service>/<baseAddresses> von "localhost" in den vollqualifizierten Namen Ihres Dienstcomputers.

  7. Kopieren Sie die Datei "Service.cer" aus dem Dienstverzeichnis in das Clientverzeichnis auf dem Clientcomputer.

  8. Führen Sie auf dem Client setup.bat client aus. Durch Ausführen von setup.bat mit dem Argument client wird ein Clientzertifikat namens "client.com" erstellt und in eine Datei namens "Client.cer" exportiert.

  9. Ändern Sie in der Client.exe.config-Datei auf dem Clientcomputer den Wert für die Adresse des Endpunkts so, dass er mit der neuen Adresse Ihres Diensts übereinstimmt. Ersetzen Sie dazu "localhost" durch den vollqualifizierten Domänennamen des Servers.

  10. Kopieren Sie die Datei "Client.cer" aus dem Clientverzeichnis in das Dienstverzeichnis auf dem Server.

  11. Führen Sie auf dem Client "ImportServiceCert.bat" aus. Dadurch wird das Dienstzertifikat aus der Datei "Service.cer" in den CurrentUser – TrustedPeople-Speicher importiert.

  12. Führen Sie auf dem Server "ImportClientCert.bat" aus. Dadurch wird das Clientzertifikat von der Datei "Client.cer" in den LocalMachine – TrustedPeople-Speicher importiert.

  13. Starten Sie auf dem Servercomputer "Service.exe" in einem Eingabeaufforderungsfenster.

  14. Starten Sie auf dem Clientcomputer "Client.exe" in einem Eingabeaufforderungsfenster. Wenn der Client und der Dienst nicht miteinander kommunizieren können, finden Sie weitere Informationen unter Hinweise zur Fehlerbehebung.

So bereinigen Sie nach dem Beispiel

  1. Führen Sie "Cleanup.bat" im Beispielordner aus, nachdem Sie das Beispiel fertig ausgeführt haben. Dadurch werden die Server- und Clientzertifikate aus dem Zertifikatspeicher entfernt.

Tipp

Wenn dieses Beispiel computerübergreifend ausgeführt wird, entfernt dieses Skript keine Dienstzertifikate auf einem Client. Wenn Sie Windows Communication Foundation (WCF)-Beispiele ausgeführt haben, die Zertifikate computerübergreifend verwenden, müssen Sie sicherstellen, dass Sie die Dienstzertifikate entfernen, die im CurrentUser – TrustedPeople-Speicher installiert wurden. Verwenden Sie dazu den folgenden Befehl: certmgr -del -r CurrentUser -s TrustedPeople -c -n <Fully Qualified Server Machine Name> Beispiel: certmgr -del -r CurrentUser -s TrustedPeople -c -n server1.contoso.com.

Send comments about this topic to Microsoft.
© 2007 Microsoft Corporation. All rights reserved.