Segurança de mensagens no serviço de enfileiramento de mensagens

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

Este exemplo é baseado no exemplo de Vinculação MSMQ Transacionada . As mensagens são encriptadas e assinadas.

Para configurar, compilar e executar o exemplo

  1. Certifique-se de ter executado 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 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 Nova, Fila Privada.

    4. Marque a caixa Transacional .

    5. Digite ServiceModelSamplesTransacted como o nome da nova fila.

  3. Para criar a edição C# ou Visual Basic .NET da solução, siga as instruções em Criando os exemplos 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 a partir da pasta de instalação de exemplo. Isso instala todos os certificados necessários para executar o exemplo.

    Nota

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

  3. Inicie Service.exe a partir de \service\bin.

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

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

Para executar o exemplo em 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 de programa 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 setup.bat com o service argumento 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 refletir o novo nome do certificado (no findValue atributo 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 setup.bat com o client argumento cria um certificado de cliente chamado client.com e exporta o certificado de cliente para um arquivo chamado Client.cer.

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

  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 importa o certificado de serviço do arquivo Service.cer para o repositório CurrentUser - TrustedPeople.

  11. No servidor, execute ImportClientCert.bat, Isso importa o certificado do cliente do arquivo Client.cer para o armazenamento LocalMachine - TrustedPeople.

  12. No computador de serviço, inicie Service.exe a partir do prompt de comando.

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

Para limpar após a amostra

  • Execute Cleanup.bat na pasta de exemplos assim que terminar de executar o exemplo.

    Nota

    Esse script não remove certificados de serviço em um cliente ao executar este exemplo em computadores. Se você tiver executado exemplos do Windows Communication Foundation (WCF) que usam certificados entre computadores, certifique-se de limpar os certificados de serviço que foram instalados no repositório CurrentUser - TrustedPeople. Para fazer isso, use o seguinte 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 requer 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 seu próprio certificado. O serviço que lê a mensagem da fila autentica o certificado do cliente com o certificado em seu armazenamento de pessoas confiáveis. Em seguida, desencripta a mensagem e envia-a para a operação de serviço.

Como a mensagem do Windows Communication Foundation (WCF) é carregada como uma carga no corpo da mensagem MSMQ, o corpo permanece criptografado no armazenamento MSMQ. Isso protege a mensagem contra a divulgação indesejada da mensagem. Observe que o próprio MSMQ não sabe se a mensagem que 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. Este é sempre o caso com o aplicativo em fila porque o serviço e o cliente não precisam estar funcionando ao mesmo tempo.

Description

O cliente de exemplo e o código de serviço são os mesmos que o exemplo de Vinculação MSMQ Transacionada com uma diferença. O contrato de operação é anotado com nível de proteção, o que sugere que a mensagem deve 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 esteja protegida usando o token necessário para identificar o serviço e o cliente, o App.config contém informações de credenciais.

A configuração do cliente especifica o certificado de serviço para autenticar o serviço. Ele usa seu armazenamento LocalMachine como o armazenamento confiável para confiar na validade do serviço. Ele também especifica o certificado do cliente que é 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 o 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 do certificado do findValue servidor é especificado no atributo 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 o controle da autenticação usando a configuração e como obter a identidade do chamador do contexto de segurança, conforme mostrado no código de exemplo a seguir:

// 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. A seguir está uma saída de exemplo 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 lotes cria o certificado do cliente. O nome do cliente especificado é usado no nome do assunto do certificado criado. O certificado é armazenado no My local da CurrentUser loja.

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

    A linha a seguir no arquivo em lotes copia o certificado do cliente para o armazenamento TrustedPeople do servidor para que o servidor possa tomar as decisões relevantes de confiança ou não-confiança. Para que um certificado instalado no repositório TrustedPeople seja confiável por um serviço WCF (Windows Communication Foundation), o modo de validação de certificado do cliente deve ser definido como PeerOrChainTrust ou PeerTrust valor. Consulte 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 lotes 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 armazenamento LocalMachine. Se o arquivo em lotes de instalação for executado com um argumento de serviço (como setup.bat service), o %SERVER_NAME% conterá o nome de domínio totalmente qualificado do computador. Caso contrário, o padrão é localhost

  • Instalando o certificado do servidor no armazenamento de certificados confiáveis do cliente.

    A linha a seguir copia o certificado do servidor para o armazenamento de pessoas confiáveis do cliente. Esta etapa é necessária porque os certificados gerados por Makecert.exe não são implicitamente confiáveis pelo sistema cliente. Se você já tiver um certificado enraizado em um certificado raiz confiável do cliente, por exemplo, um certificado emitido pela Microsoft, esta etapa de preencher o armazenamento 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
    

    Nota

    Se você estiver usando um não-E.U. Edição em inglês do Microsoft Windows, você deve editar o arquivo Setup.bat e substituir o nome da conta "NT AUTHORITY\NETWORK SERVICE" pelo seu equivalente regional.