Compartir a través de


Seguridad de mensajes mediante Message Queuing

El ejemplo de MessageSecurity muestra cómo implementar una aplicación que usa WS-Security con autenticación de certificado X.509v3 para el cliente y requiere autenticación de servidor mediante el certificado X.509v3 del servidor a través de MSMQ. A veces, la seguridad de los mensajes es más deseable para asegurarse de que los mensajes del almacén de MSMQ permanezcan cifrados y que la aplicación pueda realizar su propia autenticación del mensaje.

Este ejemplo se basa en el ejemplo Enlace MSMQ por transacciones. Los mensajes se cifran y firman.

Para configurar, compilar y ejecutar el ejemplo

  1. Asegúrese de que ha realizado el procedimiento de instalación única para los ejemplos de Windows Communication Foundation.

  2. Si el servicio se ejecuta primero, comprobará que la cola está presente. Si la cola no está presente, el servicio creará uno. Puede ejecutar primero el servicio para crear la cola o puede crear uno a través del Administrador de colas de MSMQ. Siga estos pasos para crear una cola en Windows 2008.

    1. Abra el Administrador del servidor en Visual Studio 2012.

    2. Expanda la pestaña Características.

    3. Haga clic con el botón derecho en Cola de mensajes privados y seleccione Nuevo, Cola privada.

    4. Active la casilla Transaccional.

    5. Escriba ServiceModelSamplesTransacted como nombre de la nueva cola.

  3. Para compilar la edición de C# o de Visual Basic de la solución, siga las instrucciones que aparecen en Compilación de los ejemplos de Windows Communication Foundation.

Para ejecutar el ejemplo en el mismo equipo

  1. Asegúrese de que la ruta de acceso incluye la carpeta que contiene Makecert.exe y FindPrivateKey.exe.

  2. Ejecute Setup.bat desde la carpeta de instalación de ejemplo. Esto instala todos los certificados necesarios para ejecutar el ejemplo.

    Nota

    Asegúrese de quitar los certificados ejecutando Cleanup.bat cuando haya terminado con el ejemplo. Otros ejemplos de seguridad usan los mismos certificados.

  3. Inicie Service.exe desde \service\bin.

  4. Inicie Client.exe desde \client\bin. La actividad de cliente se muestra en la aplicación de consola cliente.

  5. Si el cliente y el servicio no pueden comunicarse, consulte Sugerencias de solución de problemas para ejemplos de WCF.

Para ejecutar el ejemplo entre equipos

  1. Copie los archivos Setup.bat, Cleanup.baty ImportClientCert.bat en el equipo de servicio.

  2. Cree un directorio en el equipo cliente para los archivos binarios del cliente.

  3. Copie los archivos de programa cliente en el directorio cliente del equipo cliente. Copie también los archivos Setup.bat, Cleanup.baty ImportServiceCert.bat en el cliente.

  4. En el servidor, ejecute setup.bat service. La ejecución de setup.bat con el argumento service crea un certificado de servicio con el nombre de dominio completo del equipo y exporta el certificado de servicio a un archivo denominado Service.cer.

  5. Edite el archivo service.exe.config del servicio para reflejar el nuevo nombre del certificado (en el findValue atributo de <serviceCertificate>), que es igual que el nombre de dominio completo del equipo.

  6. Copie el archivo Service.cer del directorio de servicio en el directorio cliente del equipo cliente.

  7. En el cliente, ejecute setup.bat client. Al ejecutar setup.bat con el argumento client, se crea un certificado de cliente denominado client.com y se exporta el certificado de cliente a un archivo denominado Client.cer.

  8. En el archivo Client.exe.config del equipo cliente, cambie el valor de dirección del punto de conexión para que coincida con la nueva dirección del servicio. Para ello, reemplace localhost por el nombre de dominio completo del servidor. También debe cambiar el nombre del certificado del servicio para que sea igual que el nombre de dominio completo del equipo del servicio (en el atributo findValue del elemento defaultCertificate de serviceCertificate, bajo clientCredentials).

  9. Copie el archivo Client.cer del directorio cliente en el directorio de servicio del servidor.

  10. En el cliente, ejecute ImportServiceCert.bat. Así se importa el certificado del servicio del archivo Service.cer en el almacén CurrentUser - TrustedPeople.

  11. En el servidor, ejecute ImportClientCert.bat. De esta manera se importa el certificado de cliente del archivo Client.cer en el almacén LocalMachine - TrustedPeople.

  12. En el equipo del servicio, inicie Service.exe desde el símbolo del sistema.

  13. En el equipo cliente, ejecute Client.exe desde la línea de comandos. Si el cliente y el servicio no pueden comunicarse, consulte Sugerencias de solución de problemas para ejemplos de WCF.

Para limpiar después de la muestra.

  • Ejecute Cleanup.bat en la carpeta samples una vez que haya terminado de ejecutar el ejemplo.

    Nota

    Este script no quita certificados de servicio en un cliente al ejecutar este ejemplo entre equipos. Si ha ejecutado ejemplos de Windows Communication Foundation (WCF) que usan certificados entre equipos, asegúrese de borrar los certificados de servicio que se han instalado en el almacén CurrentUser - TrustedPeople. Para ello, use el siguiente comando: certmgr -del -r CurrentUser -s TrustedPeople -c -n <Fully Qualified Server Machine Name> Por ejemplo: certmgr -del -r CurrentUser -s TrustedPeople -c -n server1.contoso.com.

Requisitos

Este ejemplo requiere que MSMQ esté instalado y en ejecución.

Demostraciones

El cliente cifra el mensaje mediante la clave pública del servicio y firma el mensaje con su propio certificado. El servicio que lee el mensaje de la cola autentica el certificado de cliente con el certificado en su almacén de personas de confianza. Después descifra el mensaje y lo envía a la operación de servicio.

Dado que el mensaje de Windows Communication Foundation (WCF) se lleva como carga útil en el cuerpo del mensaje de MSMQ, el cuerpo permanece cifrado en el almacén de MSMQ. Esto protege el mensaje de la divulgación no deseada del mensaje. Tenga en cuenta que MSMQ en sí no es consciente de si el mensaje que está llevando está cifrado.

En el ejemplo se muestra cómo se puede usar la autenticación mutua en el nivel de mensaje con MSMQ. Los certificados se intercambian fuera de banda. Este es siempre el caso de las aplicaciones en cola de espera porque el servicio y el cliente no tienen que estar funcionando al mismo tiempo.

Descripción

El código del servicio y del cliente del ejemplo es el mismo que en el ejemplo Enlace MSMQ por transacciones, pero con una diferencia. El contrato de operación se anota con el nivel de protección, lo que sugiere que el mensaje se debe firmar y cifrar.

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

Para asegurarse de que el mensaje está protegido mediante el token necesario para identificar el servicio y el cliente, el App.config contiene información de credenciales.

La configuración del cliente especifica el certificado de servicio para autenticar el servicio. Usa su almacén LocalMachine como almacén de confianza para confiar en la validez del servicio. También especifica el certificado de cliente que se adjunta al mensaje para la autenticación de servicio del 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>

Tenga en cuenta que el modo de seguridad se establece en Message y ClientCredentialType está establecido en Certificate.

La configuración del servicio incluye un comportamiento de servicio que especifica las credenciales del servicio que se usan cuando el cliente autentica el servicio. El nombre de sujeto del certificado del servidor se especifica en el findValue atributo en el elemento <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>

En el ejemplo se muestra cómo controlar la autenticación mediante la configuración y cómo obtener la identidad del autor de la llamada del contexto de seguridad, como se muestra en el código de ejemplo siguiente:

// 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);
    }
  //…
}

Cuando se ejecuta, el código de servicio muestra la identificación del cliente. A continuación se muestra una salida de ejemplo del código de servicio:

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

Comentarios

  • Creación del certificado de cliente.

    La siguiente línea del archivo por lotes crea el certificado de cliente. El nombre de cliente especificado se usa en el nombre del asunto del certificado creado. El certificado se guarda en el almacén My, en la ubicación de almacenamiento CurrentUser.

    echo ************
    echo making client cert
    echo ************
    makecert.exe -sr CurrentUser -ss MY -a sha1 -n CN=%CLIENT_NAME% -sky exchange -pe
    
  • Instalar el certificado de cliente en el almacén de certificados de confianza del servidor.

    La siguiente línea del archivo por lotes copia el certificado de cliente en el almacén TrustedPeople del servidor para que el servidor pueda tomar las decisiones de confianza o sin confianza pertinentes. Para que un certificado instalado en el almacén TrustedPeople sea confiable para un servicio de Windows Communication Foundation (WCF), el modo de validación de certificados de cliente debe establecerse en el valor PeerOrChainTrust o PeerTrust. Consulte el ejemplo de configuración del servicio anterior para obtener información sobre cómo se puede hacer con un archivo de configuración.

    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
    
  • Creación del certificado de servidor.

    Las líneas siguientes del archivo por lotes de Setup.bat crean el certificado de servidor que se va a usar:

    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
    

    La variable %SERVER_NAME% especifica el nombre del servidor. El certificado se almacena en el almacén localMachine. Si el archivo por lotes de instalación se ejecuta con un argumento de servicio (como setup.bat service), el %SERVER_NAME% contiene el nombre de dominio completo del equipo. De lo contrario, el valor predeterminado es localhost.

  • Instalación del certificado de servidor en el almacén de certificados de confianza del cliente.

    La línea siguiente copia el certificado de servidor en el almacén de personas de confianza del cliente. Este paso es necesario porque el sistema cliente no confía implícitamente en los certificados generados por Makecert.exe. Si ya tiene un certificado que se basa en un certificado raíz de confianza de cliente (por ejemplo, un certificado emitido por Microsoft), este paso para rellenar el almacén de certificados de cliente con el certificado de servidor no es necesario.

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

    Nota

    Si está utilizando una edición de Microsoft Windows en inglés que no sea de EE. UU., debe editar el archivo Setup.bat y reemplazar el nombre de cuenta "NT AUTHORITY\NETWORK SERVICE" por su equivalente regional.