Programación de la seguridad de WCF
Este tema describe las tareas de programación fundamentales utilizadas para crear una aplicación de Windows Communication Foundation (WCF) segura. Este tema solo cubre la autenticación, confidencialidad e integridad, conocido colectivamente como seguridad de transferencia. En este tema no se cubre la autorización (el control de acceso a recursos o servicios); para obtener información sobre la autorización, vea Autorización.
Nota: |
---|
Dispone de una valiosa introducción a los conceptos de seguridad, sobre todo con respecto a WCF, en el conjunto de tutoriales sobre modelos y procedimientos de MSDN, en la Guía sobre escenarios, modelos e implementación de Web Services Enhancements (WSE) 3.0. |
La programación de la seguridad de WCF se basa en tres pasos que establecen lo siguiente: el modo de seguridad, un tipo de credencial de cliente y los valores de credenciales. Puede realizar estos pasos mediante código o configuración.
Establecimiento del modo de seguridad
Lo siguiente explica los pasos generales para programar con el modo de seguridad en WCF:
Seleccione uno de los enlaces predefinidos adecuado a sus requisitos de aplicación. Para obtener una lista de opciones de enlaces, vea Enlaces proporcionados por el sistema. De forma predeterminada, prácticamente todos los enlaces tienen la seguridad habilitada. La única excepción es la clase BasicHttpBinding (utilizando configuración, el basicHttpBinding Element).
El enlace que seleccione determina el transporte. Por ejemplo, WSHttpBinding utiliza HTTP como el transporte; NetTcpBinding utiliza TCP.
Seleccione uno de los modos de seguridad para el enlace. Tenga en cuenta que el enlace que seleccione determinará las opciones de modo disponibles. Por ejemplo, WSDualHttpBinding no permite la seguridad de transporte (no es una opción). De igual forma, ni MsmqIntegrationBinding ni NetNamedPipeBinding permiten el modo de seguridad.
Dispone de tres opciones:
Transport
La seguridad de transporte depende del mecanismo que utilice el enlace que ha seleccionado. Por ejemplo, si utiliza WSHttpBinding, el mecanismo de seguridad es Secure Sockets Layer (SSL) (también es el mecanismo para el protocolo HTTPS). Generalmente hablando, la principal ventaja de la seguridad de transporte es que proporciona un buen rendimiento independientemente del transporte que esté utilizando. No obstante, tiene dos limitaciones: la primera es que el mecanismo de transporte dicta el tipo de credencial utilizado para autenticar a un usuario. Ésta es una desventaja solo si un servicio necesita interoperar con otros servicios que exigen tipos diferentes de credenciales. La segunda es que, puesto que la seguridad no se aplica en el nivel de mensaje, la seguridad se implementa salto por salto en lugar de de extremo a extremo. Esta última limitación solo es un problema si la ruta de acceso del mensaje entre el cliente y el servicio incluye intermediarios. Para obtener más información sobre qué transporte utilizar, vea Elección del transporte. Para obtener más información sobre uso de seguridad de transporte, vea Información general de la seguridad del transporte.
Message
El modo de seguridad significa que cada mensaje incluye los encabezados y datos necesarios para mantener el mensaje protegido. Dado que la composición de los encabezados varía, puede incluir cualquier número de credenciales. Este es un factor a tener en cuenta si está interoperando con otros servicios que exigen un tipo de credencial concreto que un mecanismo de transporte no puede proporcionar o si el mensaje se debe utilizar con más de un servicio, donde cada servicio exige un tipo de credencial diferente.
Para obtener más información, vea Seguridad de los mensajes en WCF.
TransportWithMessageCredential
Esta opción utiliza el nivel de transporte para proteger la transferencia del mensaje, mientras que cada mensaje incluye las credenciales enriquecidas que necesitan otros servicios. Esto combina la ventaja de rendimiento de la seguridad de transporte con la ventaja de las credenciales enriquecidas de la seguridad de mensaje. Esto está disponible con los siguientes enlaces: BasicHttpBinding, WSFederationHttpBinding, NetPeerTcpBinding y WSHttpBinding.
Si decide utilizar la seguridad de transporte para HTTP (en otras palabras, HTTPS), debe configurar también el host con un certificado SSL y habilitar SSL en un puerto. Para obtener más información, vea Seguridad de transporte HTTP.
Si está utilizando el WSHttpBinding y no necesita establecer una sesión segura, establezca la propiedad EstablishSecurityContext en false.
Una sesión segura se produce cuando un cliente y servicio crean un canal mediante una clave simétrica (tanto el cliente como el servidor usan la misma clave durante la duración de una conversación, hasta que se cierre el diálogo).
Establecimiento del tipo de credencial de cliente
Seleccione según corresponda un tipo de credencial de cliente. Para obtener más información, vea Selección de tipos de credenciales. Los siguientes tipos de credencial de cliente están disponibles:
Windows
Certificate
Digest
Basic
UserName
NTLM
IssuedToken
Dependiendo de cómo establezca el modo, deberá establecer el tipo de credencial. Por ejemplo, si ha seleccionado el wsHttpBinding, y ha establecido el modo en "Mensaje", también puede establecer el atributo clientCredentialType del elemento Message en uno de los valores siguientes: None, Windows, UserName, Certificate y IssuedToken, como se muestra en el ejemplo de configuración siguiente.
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="myBinding">
<security mode="Message"/>
<message clientCredentialType="Windows"/>
</binding>
</bindings>
</system.serviceModel>
O bien, en el código:
Dim b As New WSHttpBinding()
b.Name = "myBinding"
b.Security.Mode = SecurityMode.Message
b.Security.Message.ClientCredentialType = MessageCredentialType.Windows
WSHttpBinding b = new WSHttpBinding();
b.Name = "myBinding";
b.Security.Mode = SecurityMode.Message;
b.Security.Message.ClientCredentialType=MessageCredentialType.Windows;
Establecimiento de valores de credenciales de servicio
Cuando selecciona un tipo de credencial de cliente, debe establecer las credenciales reales que el servicio y el cliente han de utilizar. En el servicio, las credenciales se establecen utilizando la clase ServiceCredentials y se devuelven mediante la propiedad Credentials de la clase ServiceHostBase. El enlace en uso implica el tipo de credencial de servicio, el modo de seguridad elegido y el tipo de la credencial de cliente. El código siguiente establece un certificado para una credencial de servicio.
' Create the binding for an endpoint.
Dim b As New NetTcpBinding()
b.Security.Mode = SecurityMode.Message
' Create the ServiceHost for a calculator.
Dim baseUri As New Uri("net.tcp://MachineName/tcpBase")
Dim baseAddresses() As Uri = {baseUri}
Dim sh As New ServiceHost(GetType(Calculator), baseAddresses)
' Add an endpoint using the binding and a new address.
Dim c As Type = GetType(ICalculator)
sh.AddServiceEndpoint(c, b, "MyEndpoint")
' Set a certificate as the credential for the service.
sh.Credentials.ServiceCertificate.SetCertificate( _
StoreLocation.LocalMachine, _
StoreName.My, _
X509FindType.FindBySubjectName, _
"contoso.com")
Try
sh.Open()
Console.WriteLine("Listening....")
Console.ReadLine()
sh.Close()
Catch ce As CommunicationException
Console.WriteLine("A commmunication error occurred: {0}", ce.Message)
Console.WriteLine()
Catch exc As System.Exception
Console.WriteLine("An unforseen error occurred: {0}", exc.Message)
Console.ReadLine()
End Try
// Create the binding for an endpoint.
NetTcpBinding b = new NetTcpBinding();
b.Security.Mode = SecurityMode.Message;
// Create the ServiceHost for a calculator.
Uri baseUri = new Uri("net.tcp://MachineName/tcpBase");
Uri[] baseAddresses = new Uri[] { baseUri };
ServiceHost sh = new ServiceHost(typeof(Calculator), baseAddresses);
// Add an endpoint using the binding and a new address.
Type c = typeof(ICalculator);
sh.AddServiceEndpoint(c, b, "MyEndpoint");
// Set a certificate as the credential for the service.
sh.Credentials.ServiceCertificate.SetCertificate(
StoreLocation.LocalMachine,
StoreName.My,
X509FindType.FindBySubjectName,
"client.com");
try
{
sh.Open();
Console.WriteLine("Listening....");
Console.ReadLine();
sh.Close();
}
catch (CommunicationException ce)
{
Console.WriteLine("A commmunication error occurred: {0}", ce.Message);
Console.WriteLine();
}
catch (System.Exception exc)
{
Console.WriteLine("An unforseen error occurred: {0}", exc.Message);
Console.ReadLine();
}
Establecimiento de los valores de credencial de cliente
En el cliente, establezca valores de credencial de cliente mediante la clase ClientCredentials y devueltos por la propiedad ClientCredentials de la clase ClientBase. El código siguiente establece un certificado como una credencial en un cliente utilizando el protocolo TCP.
' Create a NetTcpBinding and set its security properties. The
' security mode is Message, and the client must be authenticated with
' Windows. Therefore the client must be on the same Windows domain.
Dim b As New NetTcpBinding()
b.Security.Mode = SecurityMode.Message
b.Security.Message.ClientCredentialType = MessageCredentialType.Windows
' Set a Type variable for use when constructing the endpoint.
Dim c As Type = GetType(ICalculator)
' Create a base address for the service.
Dim tcpBaseAddress As New Uri("net.tcp://machineName.Domain.Contoso.com:8036/serviceName")
' The base address is in an array of URI objects.
Dim baseAddresses() As Uri = {tcpBaseAddress}
' Create the ServiceHost with type and base addresses.
Dim sh As New ServiceHost(GetType(CalculatorClient), baseAddresses)
' Add an endpoint to the service using the service type and binding.
sh.AddServiceEndpoint(c, b, "")
sh.Open()
Dim address As String = sh.Description.Endpoints(0).ListenUri.AbsoluteUri
Console.WriteLine("Listening @ {0}", address)
Console.WriteLine("Press enter to close the service")
Console.ReadLine()
// Create a NetTcpBinding and set its security properties. The
// security mode is Message, and the client must be authenticated with
// Windows. Therefore the client must be on the same Windows domain.
NetTcpBinding b = new NetTcpBinding();
b.Security.Mode = SecurityMode.Message;
b.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
// Set a Type variable for use when constructing the endpoint.
Type c = typeof(ICalculator);
// Create a base address for the service.
Uri tcpBaseAddress =
new Uri("net.tcp://machineName.Domain.Contoso.com:8036/serviceName");
// The base address is in an array of URI objects.
Uri[] baseAddresses = new Uri[] { tcpBaseAddress };
// Create the ServiceHost with type and base addresses.
ServiceHost sh = new ServiceHost(typeof(CalculatorClient), baseAddresses);
// Add an endpoint to the service using the service type and binding.
sh.AddServiceEndpoint(c, b, "");
sh.Open();
string address = sh.Description.Endpoints[0].ListenUri.AbsoluteUri;
Console.WriteLine("Listening @ {0}", address);
Console.WriteLine("Press enter to close the service");
Console.ReadLine();