Delen via


X.509 Certificate Validator

In dit voorbeeld ziet u hoe u een aangepaste X.509 Certificate Validator implementeert. Dit is handig in gevallen waarin geen van de ingebouwde X.509-certificaatvalidatiemodi geschikt is voor de vereisten van de toepassing. In dit voorbeeld ziet u een service met een aangepaste validator die zelfuitgeschreven certificaten accepteert. De client gebruikt een dergelijk certificaat om te verifiëren bij de service.

Opmerking: Aangezien iedereen een zelf uitgegeven certificaat kan maken, is de aangepaste validator die door de service wordt gebruikt, minder veilig dan het standaardgedrag dat wordt geleverd door chaintrust X509CertificateValidationMode. De gevolgen voor de beveiliging hiervan moeten zorgvuldig worden overwogen voordat u deze validatielogica in productiecode gebruikt.

In het kort laat dit voorbeeld zien hoe:

  • De client kan worden geverifieerd met behulp van een X.509-certificaat.

  • De server valideert de clientreferenties op basis van een aangepaste X509CertificateValidator.

  • De server wordt geverifieerd met het X.509-certificaat van de server.

De service maakt één eindpunt beschikbaar voor communicatie met de service, gedefinieerd met behulp van het configuratiebestand App.config. Het eindpunt bestaat uit een adres, een binding en een contract. De binding wordt geconfigureerd met een standaard wsHttpBinding die standaard wordt gebruikt voor het gebruik van WSSecurity en clientcertificaatverificatie. Het servicegedrag geeft de aangepaste modus op voor het valideren van X.509-certificaten van de client, samen met het type validatieklasse. Het gedrag geeft ook het servercertificaat op met behulp van het element serviceCertificate. Het servercertificaat moet dezelfde waarde bevatten als SubjectName de in serviceCertificate><.findValue

  <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 =
                "http://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>

De configuratie van het clienteindpunt bestaat uit een configuratienaam, een absoluut adres voor het service-eindpunt, de binding en het contract. De clientbinding is geconfigureerd met de juiste modus en het juiste bericht clientCredentialType.

<system.serviceModel>
    <client>
      <!-- X509 certificate based endpoint -->
      <endpoint name="Certificate"
        address=
        "http://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>

De client-implementatie stelt het clientcertificaat in dat moet worden gebruikt.

// 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 dit voorbeeld wordt een aangepaste X509CertificateValidator gebruikt om certificaten te valideren. Het voorbeeld implementeert CustomX509CertificateValidator, afgeleid van X509CertificateValidator. Raadpleeg de documentatie voor X509CertificateValidator meer informatie. Met dit aangepaste validatievoorbeeld wordt de validatiemethode geïmplementeerd om een X.509-certificaat te accepteren dat zelf is uitgegeven, zoals wordt weergegeven in de volgende code.

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");
   }
}

Zodra de validator is geïmplementeerd in de servicecode, moet de servicehost worden geïnformeerd over het validator-exemplaar dat moet worden gebruikt. Dit wordt gedaan met behulp van de volgende code.

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

Of u kunt hetzelfde doen in de configuratie als volgt.

<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>
   </serviceCredentials>
   ...
  </behavior>
 </serviceBehaviors>
</behaviors>

Wanneer u het voorbeeld uitvoert, worden de bewerkingsaanvragen en -antwoorden weergegeven in het clientconsolevenster. De client moet alle methoden aanroepen. Druk op Enter in het clientvenster om de client af te sluiten.

Batch-bestand instellen

Met het Setup.bat batchbestand dat is opgenomen in dit voorbeeld, kunt u de server configureren met relevante certificaten om een zelf-hostende toepassing uit te voeren waarvoor beveiliging op basis van servercertificaten is vereist. Dit batchbestand moet worden gewijzigd om te kunnen werken op computers of om te kunnen werken in een niet-gehost geval.

Hieronder vindt u een kort overzicht van de verschillende secties van de batchbestanden, zodat ze kunnen worden gewijzigd om te worden uitgevoerd in de juiste configuratie:

  • Het servercertificaat maken:

    De volgende regels uit het Setup.bat batchbestand maken het servercertificaat dat moet worden gebruikt. De variabele %SERVER_NAME% geeft de servernaam op. Wijzig deze variabele om uw eigen servernaam op te geven. De standaardwaarde is 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
    
  • Het servercertificaat installeren in het vertrouwde certificaatarchief van de client:

    Met de volgende regels in het Setup.bat batchbestand kopieert u het servercertificaat naar het archief vertrouwde personen van de client. Deze stap is vereist omdat certificaten die worden gegenereerd door Makecert.exe niet impliciet worden vertrouwd door het clientsysteem. Als u al een certificaat hebt dat is geroot in een vertrouwd basiscertificaat van een client, bijvoorbeeld een door Microsoft uitgegeven certificaat, is deze stap van het vullen van het clientcertificaatarchief met het servercertificaat niet vereist.

    certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r CurrentUser -s TrustedPeople
    
  • Het clientcertificaat maken:

    Met de volgende regels uit het Setup.bat batchbestand maakt u het clientcertificaat dat moet worden gebruikt. De variabele %USER_NAME% geeft de clientnaam op. Deze waarde is ingesteld op 'test1', omdat dit de naam is die de clientcode zoekt. Als u de waarde van %USER_NAME% wijzigt, moet u de bijbehorende waarde in het Client.cs bronbestand wijzigen en de client opnieuw opbouwen.

    Het certificaat wordt opgeslagen in mijn (persoonlijke) archief onder de locatie van het CurrentUser-archief.

    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
    
  • Het clientcertificaat installeren in het vertrouwde certificaatarchief van de server:

    Met de volgende regels in het Setup.bat batchbestand kopieert u het clientcertificaat naar het archief met vertrouwde personen. Deze stap is vereist omdat certificaten die worden gegenereerd door Makecert.exe niet impliciet worden vertrouwd door het serversysteem. Als u al een certificaat hebt dat is geroot in een vertrouwd basiscertificaat, bijvoorbeeld een door Microsoft uitgegeven certificaat, is deze stap van het vullen van het servercertificaatarchief met het clientcertificaat niet vereist.

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

Het voorbeeld instellen en bouwen

  1. Volg de instructies in Het bouwen van de Windows Communication Foundation-voorbeelden om de oplossing te bouwen.

  2. Als u het voorbeeld wilt uitvoeren in een configuratie van één of meerdere computers, gebruikt u de volgende instructies.

Het voorbeeld uitvoeren op dezelfde computer

  1. Voer Setup.bat uit vanuit de voorbeeldinstallatiemap in een Visual Studio-opdrachtprompt die is geopend met beheerdersbevoegdheden. Hiermee worden alle certificaten geïnstalleerd die vereist zijn voor het uitvoeren van het voorbeeld.

    Belangrijk

    Het Setup.bat batchbestand is ontworpen om te worden uitgevoerd vanaf een Visual Studio-opdrachtprompt. De omgevingsvariabele PATH die in de Visual Studio-opdrachtprompt is ingesteld, verwijst naar de map met uitvoerbare bestanden die zijn vereist voor het Setup.bat script.

  2. Start Service.exe vanuit service\bin.

  3. Start Client.exe vanuit \client\bin. Clientactiviteit wordt weergegeven in de clientconsoletoepassing.

  4. Als de client en service niet kunnen communiceren, raadpleegt u Tips voor probleemoplossing voor WCF-voorbeelden.

Het voorbeeld uitvoeren op computers

  1. Maak een map op de servicecomputer.

  2. Kopieer de serviceprogrammabestanden van \service\bin naar de virtuele map op de servicecomputer. Kopieer ook de Setup.bat, Cleanup.bat, GetComputerName.vbs en ImportClientCert.bat bestanden naar de servicecomputer.

  3. Maak een map op de clientcomputer voor de binaire clientbestanden.

  4. Kopieer de clientprogrammabestanden naar de clientmap op de clientcomputer. Kopieer ook de bestanden Setup.bat, Cleanup.bat en ImportServiceCert.bat naar de client.

  5. Voer setup.bat service op de server uit in een opdrachtprompt voor ontwikkelaars voor Visual Studio die is geopend met beheerdersbevoegdheden. Als u het service argument uitvoertsetup.bat, maakt u een servicecertificaat met de volledig gekwalificeerde domeinnaam van de computer en exporteert u het servicecertificaat naar een bestand met de naam Service.cer.

  6. Bewerk Service.exe.config om de nieuwe certificaatnaam (in het findValue kenmerk in serviceCertificate <) weer te> geven. Dit is hetzelfde als de volledig gekwalificeerde domeinnaam van de computer. Wijzig ook de computernaam in het <element service>/<baseAddresses> van localhost in volledig gekwalificeerde naam van uw servicecomputer.

  7. Kopieer het Service.cer-bestand van de servicemap naar de clientmap op de clientcomputer.

  8. Voer setup.bat client op de client uit in een opdrachtprompt voor ontwikkelaars voor Visual Studio die is geopend met beheerdersbevoegdheden. Als u het argument uitvoert setup.bat , maakt u een clientcertificaat met de client naam client.com en exporteert u het clientcertificaat naar een bestand met de naam Client.cer.

  9. Wijzig in het bestand Client.exe.config op de clientcomputer de adreswaarde van het eindpunt zodat deze overeenkomt met het nieuwe adres van uw service. Doe dit door localhost te vervangen door de volledig gekwalificeerde domeinnaam van de server.

  10. Kopieer het Client.cer-bestand van de clientmap naar de servicemap op de server.

  11. Voer op de client ImportServiceCert.bat uit in een opdrachtprompt voor ontwikkelaars voor Visual Studio die is geopend met beheerdersbevoegdheden. Hiermee importeert u het servicecertificaat uit het Service.cer-bestand in het CurrentUser - Trusted Mensen-archief.

  12. Voer op de server ImportClientCert.bat uit in een opdrachtprompt voor ontwikkelaars voor Visual Studio die is geopend met beheerdersbevoegdheden. Hiermee importeert u het clientcertificaat uit het Client.cer-bestand in het LocalMachine - Trusted Mensen-archief.

  13. Start Service.exe op de servercomputer vanuit het opdrachtpromptvenster.

  14. Start Client.exe vanaf een opdrachtpromptvenster op de clientcomputer. Als de client en service niet kunnen communiceren, raadpleegt u Tips voor probleemoplossing voor WCF-voorbeelden.

Opschonen na het voorbeeld

  1. Voer Cleanup.bat uit in de map met voorbeelden zodra u klaar bent met het uitvoeren van het voorbeeld. Hiermee worden de server- en clientcertificaten uit het certificaatarchief verwijderd.

Notitie

Dit script verwijdert geen servicecertificaten op een client bij het uitvoeren van dit voorbeeld op computers. Als u WCF-voorbeelden (Windows Communication Foundation) hebt uitgevoerd die gebruikmaken van certificaten op computers, moet u de servicecertificaten wissen die zijn geïnstalleerd in het CurrentUser - Trusted Mensen-archief. Gebruik hiervoor de volgende opdracht: bijvoorbeeld: certmgr -del -r CurrentUser -s TrustedPeople -c -n <Fully Qualified Server Machine Name>certmgr -del -r CurrentUser -s TrustedPeople -c -n server1.contoso.com.