Compartilhar via


Segurança de mensagem através do enfileiramento de mensagem

O exemplo de MessageSecurity demonstra como implementar um aplicativo que usa o WS-Security com autenticação de certificado X.509v3 para o cliente e exige a autenticação de servidor usando o certificado X.509v3 do servidor no MSMQ. Às vezes, a segurança da mensagem é mais desejável para garantir que as mensagens no repositório do MSMQ permaneçam criptografadas e que o aplicativo possa executar uma autenticação própria da mensagem.

Este exemplo se baseia no exemplo de Associação transacionada do MSMQ. As mensagens são criptografadas e assinadas.

Para configurar, compilar, e executar o exemplo

  1. Verifique se você executou o Procedimento de instalação única para os exemplos do Windows Communication Foundation.

  2. Se o serviço for executado primeiro, ele verificará se a fila está presente. Se a fila não estiver presente, o serviço criará uma. Você pode executar o serviço primeiro para criar a fila ou pode criar uma por meio do Gerenciador de Filas do MSMQ. Siga estas etapas para criar uma fila no Windows 2008.

    1. Abra o Gerenciador do Servidor no Visual Studio 2012.

    2. Expanda a guia Recursos.

    3. Clique com o botão direito do mouse em Filas de Mensagens Privadas e selecione NovaFila Privada.

    4. Marque a caixa Transacional.

    5. Insira ServiceModelSamplesTransacted como o nome da nova fila.

  3. Para compilar a edição .NET do C# ou do Visual Basic da solução, siga as instruções contidas em Como Compilar as Amostras do Windows Communication Foundation.

Para executar o exemplo no mesmo computador

  1. Verifique se o caminho inclui a pasta que contém Makecert.exe e FindPrivateKey.exe.

  2. Execute Setup.bat na pasta de instalação do exemplo. Isso instalará todos os certificados necessários para executar o exemplo.

    Observação

    Lembre-se de remover os certificados executando Cleanup.bat quando terminar de usar o exemplo. Outros exemplos de segurança usam os mesmos certificados.

  3. Inicie Service.exe por meio de \service\bin.

  4. Inicialize o Client.exe a partir do \client\bin. A atividade do cliente é exibida no aplicativo do console do cliente.

  5. Se o cliente e o serviço não puderem se comunicar, confira Dicas de solução de problemas para exemplos de WCF.

Para executar o exemplo em vários computadores

  1. Copie os arquivos Setup.bat, Cleanup.bat e ImportClientCert.bat para o computador de serviço.

  2. Crie um diretório no computador cliente para os binários do cliente.

  3. Copie os arquivos do programa do cliente para o diretório do cliente no computador cliente. Copie também os arquivos Setup.bat, Cleanup.bat e ImportServiceCert.bat para o cliente.

  4. No servidor, execute setup.bat service. A execução de setup.bat com o argumento service cria um certificado de serviço com o nome de domínio totalmente qualificado do computador e exporta o certificado de serviço para um arquivo chamado Service.cer.

  5. Edite o service.exe.config do serviço para que ele reflita o novo nome do certificado (no atributo findValue no <serviceCertificate>), que é o mesmo que o nome de domínio totalmente qualificado do computador.

  6. Copie o arquivo Service.cer do diretório de serviço para o diretório do cliente no computador cliente.

  7. No cliente, execute setup.bat client. A execução de setup.bat com o argumento client cria um certificado de cliente chamado client.com e exporta o certificado do cliente para um arquivo chamado Client.cer.

  8. No arquivo Client.exe.config do computador cliente, altere o valor do endereço do ponto de extremidade para que ele corresponda ao novo endereço do serviço. Faça isso substituindo localhost pelo nome de domínio totalmente qualificado do servidor. Você também precisa alterar o nome do certificado do serviço para que ele tenha o mesmo nome de domínio totalmente qualificado do computador de serviço (no atributo findValue do elemento defaultCertificate de serviceCertificate em clientCredentials).

  9. Copie o arquivo Client.cer do diretório do cliente para o diretório de serviço no servidor.

  10. No cliente, execute ImportServiceCert.bat. Isso importará o certificado de serviço do arquivo Service.cer para o repositório CurrentUser - TrustedPeople.

  11. No servidor, execute ImportClientCert.bat. Isso importará o certificado do cliente do arquivo Client.cer para o repositório LocalMachine – TrustedPeople.

  12. No computador de serviço, inicie Service.exe no prompt de comando.

  13. No computador cliente, inicie Client.exe no prompt de comando. Se o cliente e o serviço não puderem se comunicar, confira Dicas de solução de problemas para exemplos de WCF.

Para fazer uma limpeza após o exemplo

  • Execute Cleanup.bat na pasta de amostras depois de concluir a execução da amostra.

    Observação

    Esse script não remove os certificados de serviço em um cliente na execução dessa amostra em vários computadores. Se você tiver executado exemplos do WCF (Windows Communication Foundation) que usam certificados em computadores, lembre-se de limpar os certificados de serviço que foram instalados no repositório CurrentUser – TrustedPeople. Para fazer isso, use a seguinte linha de comando: certmgr -del -r CurrentUser -s TrustedPeople -c -n <Fully Qualified Server Machine Name> Por exemplo: certmgr -del -r CurrentUser -s TrustedPeople -c -n server1.contoso.com.

Requisitos

Este exemplo exige que o MSMQ esteja instalado e em execução.

Demonstra

O cliente criptografa a mensagem usando a chave pública do serviço e assina a mensagem usando um certificado próprio. O serviço que lê a mensagem da fila autentica o certificado do cliente com o certificado no repositório de pessoas confiáveis. Em seguida, descriptografa a mensagem e envia a mensagem para a operação de serviço.

Como a mensagem do WCF (Windows Communication Foundation) é carregada como um conteúdo no corpo da mensagem do MSMQ, o corpo permanece criptografado no repositório do MSMQ. Isso protege a mensagem contra divulgação indesejada. Observe que o MSMQ em si não está ciente se a mensagem que ele está carregando está criptografada.

O exemplo demonstra como a autenticação mútua no nível da mensagem pode ser usada com o MSMQ. Os certificados são trocados fora da banda. Esse é sempre o caso com o aplicativo na fila porque o serviço e o cliente não precisam estar em execução ao mesmo tempo.

Descrição

O exemplo de cliente e o código de serviço é o mesmo que o exemplo de Associação transacionada do MSMQ com uma diferença. O contrato de operação é anotado com o nível de proteção, o que sugere que a mensagem precisa ser assinada e criptografada.

// Define a service contract.
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IOrderProcessor
{
    [OperationContract(IsOneWay = true, ProtectionLevel=ProtectionLevel.EncryptAndSign)]
    void SubmitPurchaseOrder(PurchaseOrder po);
}

Para garantir que a mensagem seja protegida usando o token necessário para identificar o serviço e o cliente, o App.config contém informações de credencial.

A configuração do cliente especifica o certificado de serviço usado para autenticar o serviço. Ele usa o repositório LocalMachine como o repositório confiável para depender da validade do serviço. Também especifica o certificado do cliente anexado com a mensagem para autenticação de serviço do cliente.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <system.serviceModel>

    <client>
      <!-- Define NetMsmqEndpoint -->
      <endpoint address="net.msmq://localhost/private/ServiceModelSamplesMessageSecurity"
                binding="netMsmqBinding"
                bindingConfiguration="messageSecurityBinding"
                contract="Microsoft.ServiceModel.Samples.IOrderProcessor"
                behaviorConfiguration="ClientCertificateBehavior" />
    </client>

    <bindings>
        <netMsmqBinding>
            <binding name="messageSecurityBinding">
                <security mode="Message">
                    <message clientCredentialType="Certificate"/>
                </security>
            </binding>
        </netMsmqBinding>
    </bindings>

    <behaviors>
      <endpointBehaviors>
        <behavior name="ClientCertificateBehavior">
          <!--
        The clientCredentials behavior allows one to define a certificate to present to a service.
        A certificate is used by a client to authenticate itself to the service and provide message integrity.
        This configuration references the "client.com" certificate installed during the setup instructions.
        -->
          <clientCredentials>
            <clientCertificate findValue="client.com" storeLocation="CurrentUser" storeName="My" x509FindType="FindBySubjectName" />
            <serviceCertificate>
                <defaultCertificate findValue="localhost" storeLocation="CurrentUser" storeName="TrustedPeople" x509FindType="FindBySubjectName"/>
              <!--
            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>
</configuration>

Observe que o modo de segurança está definido como Message e ClientCredentialType está definido como Certificate.

A configuração do serviço inclui um comportamento de serviço que especifica as credenciais do serviço que são usadas quando o cliente autentica o serviço. O nome da entidade de certificado do servidor é especificado no atributo findValue em <serviceCredentials>.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <appSettings>
    <!-- Use appSetting to configure MSMQ queue name. -->
    <add key="queueName" value=".\private$\ServiceModelSamplesMessageSecurity" />
  </appSettings>

  <system.serviceModel>
    <services>
      <service
          name="Microsoft.ServiceModel.Samples.OrderProcessorService"
          behaviorConfiguration="PurchaseOrderServiceBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8000/ServiceModelSamples/service"/>
          </baseAddresses>
        </host>
        <!-- Define NetMsmqEndpoint -->
        <endpoint address="net.msmq://localhost/private/ServiceModelSamplesMessageSecurity"
                  binding="netMsmqBinding"
                  bindingConfiguration="messageSecurityBinding"
                  contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
        <!-- The mex endpoint is exposed at http://localhost:8000/ServiceModelSamples/service/mex. -->
        <endpoint address="mex"
                  binding="mexHttpBinding"
                  contract="IMetadataExchange" />
      </service>
    </services>

    <bindings>
        <netMsmqBinding>
            <binding name="messageSecurityBinding">
                <security mode="Message">
                    <message clientCredentialType="Certificate" />
                </security>
            </binding>
        </netMsmqBinding>
    </bindings>

    <behaviors>
      <serviceBehaviors>
        <behavior name="PurchaseOrderServiceBehavior">
          <serviceMetadata httpGetEnabled="True"/>
          <!--
               The serviceCredentials behavior allows one to define a service certificate.
               A service certificate is used by the service to authenticate itself to its clients and to provide message protection.
               This configuration references the "localhost" certificate installed during the setup instructions.
          -->
          <serviceCredentials>
            <serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
            <clientCertificate>
                <certificate findValue="client.com" storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName"/>
              <!--
            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" />
            </clientCertificate>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>

  </system.serviceModel>

</configuration>

O exemplo demonstra como controlar a autenticação usando a configuração e como obter a identidade do chamador do contexto de segurança, conforme mostrado no seguinte código de exemplo:

// Service class which implements the service contract.
// Added code to write output to the console window.
public class OrderProcessorService : IOrderProcessor
{
    private string GetCallerIdentity()
    {
        // The client certificate is not mapped to a Windows identity by default.
        // ServiceSecurityContext.PrimaryIdentity is populated based on the information
        // in the certificate that the client used to authenticate itself to the service.
        return ServiceSecurityContext.Current.PrimaryIdentity.Name;
    }

    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
    public void SubmitPurchaseOrder(PurchaseOrder po)
    {
        Console.WriteLine("Client's Identity {0} ", GetCallerIdentity());
        Orders.Add(po);
        Console.WriteLine("Processing {0} ", po);
    }
  //…
}

Quando executado, o código de serviço exibe a identificação do cliente. Este é um exemplo de saída do código de serviço:

The service is ready.
Press <ENTER> to terminate service.

Client's Identity CN=client.com; ECA6629A3C695D01832D77EEE836E04891DE9D3C
Processing Purchase Order: 6536e097-da96-4773-9da3-77bab4345b5d
        Customer: somecustomer.com
        OrderDetails
                Order LineItem: 54 of Blue Widget @unit price: $29.99
                Order LineItem: 890 of Red Widget @unit price: $45.89
        Total cost of this order: $42461.56
        Order status: Pending

Comentários

  • Criação do certificado do cliente.

    A linha a seguir no arquivo em lote cria o certificado do cliente. O nome do cliente especificado é usado no nome da entidade do certificado criado. O certificado é armazenado no repositório My no local do repositório CurrentUser.

    echo ************
    echo making client cert
    echo ************
    makecert.exe -sr CurrentUser -ss MY -a sha1 -n CN=%CLIENT_NAME% -sky exchange -pe
    
  • Instalação do certificado do cliente no repositório de certificados confiáveis do servidor.

    A linha a seguir do arquivo em lote copia o certificado do cliente no repositório TrustedPeople do servidor para que o servidor possa tomar as decisões relevantes de relação de confiança ou sem relação de confiança. Para que um certificado instalado no repositório TrustedPeople seja confiável para um serviço WCF (Windows Communication Foundation), o modo de validação de certificado do cliente precisa ser definido como o valor PeerOrChainTrust ou PeerTrust. Confira o exemplo de configuração de serviço anterior para saber como isso pode ser feito usando um arquivo de configuração.

    echo ************
    echo copying client cert to server's LocalMachine store
    echo ************
    certmgr.exe -add -r CurrentUser -s My -c -n %CLIENT_NAME% -r LocalMachine -s TrustedPeople
    
  • Criação do certificado do servidor.

    As seguintes linhas do arquivo em lote Setup.bat criam o certificado do servidor a ser usado:

    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
    

    A variável %SERVER_NAME% especifica o nome do servidor. O certificado é armazenado no repositório LocalMachine. Se o arquivo em lote de instalação for executado com um argumento de serviço (por exemplo, setup.bat service), o %SERVER_NAME% conterá o nome de domínio totalmente qualificado do computador. Caso contrário, ele usará localhost como padrão

  • Instalação do certificado do servidor no repositório de certificados confiáveis do cliente.

    A linha a seguir copia o certificado do servidor para o repositório de pessoas confiáveis do cliente. Essa etapa é necessária porque os certificados gerados por Makecert.exe não são implicitamente confiáveis pelo sistema do cliente. Se você já tiver um certificado com raiz em um certificado raiz confiável do cliente, por exemplo, um certificado emitido pela Microsoft, essa etapa de preenchimento do repositório de certificados do cliente com o certificado do servidor não será necessária.

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

    Observação

    Se você estiver usando uma edição do Microsoft Windows em inglês que não seja dos EUA, edite o arquivo Setup.bat e substitua o nome da conta "NT AUTHORITY\NETWORK SERVICE" pelo equivalente regional.