Programação WCF Segurança
Este tópico descreve as tarefas fundamentais de programação usadas para criar um aplicativo Windows Communication Foundation (WCF) seguro. Este tópico aborda apenas autenticação, confidencialidade e integridade, conhecidas coletivamente como segurança de transferência. Este tópico não abrange autorização (o controle de acesso a recursos ou serviços); para obter informações sobre autorização, consulte Autorização.
Nota
Para obter uma introdução valiosa aos conceitos de segurança, especialmente em relação ao WCF, consulte o conjunto de tutoriais de padrões e práticas no MSDN em Cenários, padrões e diretrizes de implementação para aprimoramentos de serviços da Web (WSE) 3.0.
A programação da segurança do WCF é baseada em três etapas que definem o seguinte: o modo de segurança, um tipo de credencial de cliente e os valores de credencial. Você pode executar essas etapas por meio de código ou configuração.
Definindo o modo de segurança
A seguir explica as etapas gerais para programação com o modo de segurança no WCF:
Selecione uma das associações predefinidas apropriadas aos requisitos do seu aplicativo. Para obter uma lista das opções de vinculação, consulte Ligações fornecidas pelo sistema. Por padrão, quase todas as associações têm a segurança habilitada. A única exceção é a classe (usando configuração BasicHttpBinding , o <basicHttpBinding>).
A associação selecionada determina o transporte. Por exemplo, WSHttpBinding usa HTTP como transporte, NetTcpBinding usa TCP.
Selecione um dos modos de segurança para a ligação. Observe que a associação selecionada determina as opções de modo disponíveis. Por exemplo, o não permite segurança de WSDualHttpBinding transporte (não é uma opção). Da mesma forma, nem o MsmqIntegrationBinding nem o NetNamedPipeBinding permite a segurança da mensagem.
Você tem três opções:
Transport
A segurança do transporte depende do mecanismo usado pela associação selecionada. Por exemplo, se você estiver usando
WSHttpBinding
, o mecanismo de segurança é Secure Sockets Layer (SSL) (também o mecanismo para o protocolo HTTPS). De um modo geral, a principal vantagem da segurança de transporte é que proporciona um bom rendimento, independentemente do transporte que estiver a utilizar. No entanto, ele tem duas limitações: A primeira é que o mecanismo de transporte dita o tipo de credencial usado para autenticar um usuário. Essa é uma desvantagem apenas se um serviço precisar interoperar com outros serviços que exigem diferentes tipos de credenciais. A segunda é que, como a segurança não é aplicada no nível da mensagem, a segurança é implementada de forma hop-by-hop em vez de end-to-end. Esta última limitação é um problema apenas se o caminho da mensagem entre o cliente e o serviço incluir intermediários. Para obter mais informações sobre qual transporte usar, consulte Escolhendo um transporte. Para obter mais informações sobre como usar a segurança de transporte, consulte Visão geral da segurança de transporte.Message
Segurança de mensagem significa que cada mensagem inclui os cabeçalhos e dados necessários para manter a mensagem segura. Como a composição dos cabeçalhos varia, você pode incluir qualquer número de credenciais. Isso se torna um fator se você estiver interoperando com outros serviços que exigem um tipo de credencial específico que um mecanismo de transporte não pode fornecer, ou se a mensagem deve ser usada com mais de um serviço, onde cada serviço exige um tipo de credencial diferente.
Para obter mais informações, consulte Segurança de mensagens.
TransportWithMessageCredential
Essa opção usa a camada de transporte para proteger a transferência de mensagens, enquanto cada mensagem inclui as credenciais avançadas de que outros serviços precisam. Isso combina a vantagem de desempenho da segurança de transporte com a vantagem de credenciais avançadas da segurança de mensagens. Isso está disponível com as seguintes associações: BasicHttpBinding, WSFederationHttpBinding, NetPeerTcpBinding, e WSHttpBinding.
Se você decidir usar a segurança de transporte para HTTP (em outras palavras, HTTPS), também deverá configurar o host com um certificado SSL e habilitar o SSL em uma porta. Para obter mais informações, consulte Segurança de transporte HTTP.
Se você estiver usando o WSHttpBinding e não precisar estabelecer uma sessão segura, defina a EstablishSecurityContext propriedade como
false
.Uma sessão segura ocorre quando um cliente e um serviço criam um canal usando uma chave simétrica (cliente e servidor usam a mesma chave durante uma conversa, até que a caixa de diálogo seja fechada).
Definindo o tipo de credencial do cliente
Selecione um tipo de credencial de cliente conforme apropriado. Para obter mais informações, consulte Selecionando um tipo de credencial. Os seguintes tipos de credenciais de cliente estão disponíveis:
Windows
Certificate
Digest
Basic
UserName
NTLM
IssuedToken
Dependendo de como você define o modo, você deve definir o tipo de credencial. Por exemplo, se você selecionou o wsHttpBinding
, e definiu o modo como "Mensagem", também pode definir o clientCredentialType
atributo do elemento Message para um dos seguintes valores: None
, Windows
, UserName
, Certificate
, e IssuedToken
, conforme mostrado no exemplo de configuração a seguir.
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="myBinding">
<security mode="Message"/>
<message clientCredentialType="Windows"/>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
Ou no código:
WSHttpBinding b = new WSHttpBinding();
b.Name = "myBinding";
b.Security.Mode = SecurityMode.Message;
b.Security.Message.ClientCredentialType=MessageCredentialType.Windows;
Dim b As New WSHttpBinding()
b.Name = "myBinding"
b.Security.Mode = SecurityMode.Message
b.Security.Message.ClientCredentialType = MessageCredentialType.Windows
Definindo valores de credenciais de serviço
Depois de selecionar um tipo de credencial de cliente, você deve definir as credenciais reais para o serviço e o cliente usarem. No serviço, as credenciais são definidas usando a ServiceCredentials classe e retornadas pela Credentials propriedade da ServiceHostBase classe. A associação em uso implica o tipo de credencial de serviço, o modo de segurança escolhido e o tipo de credencial de cliente. O código a seguir define um certificado para uma credencial de serviço.
// 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 communication error occurred: {0}", ce.Message);
Console.WriteLine();
}
catch (System.Exception exc)
{
Console.WriteLine("An unforeseen error occurred: {0}", exc.Message);
Console.ReadLine();
}
' 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 communication error occurred: {0}", ce.Message)
Console.WriteLine()
Catch exc As System.Exception
Console.WriteLine("An unforeseen error occurred: {0}", exc.Message)
Console.ReadLine()
End Try
Definindo valores de credenciais de cliente
No cliente, defina valores de credenciais de cliente usando a ClientCredentials classe e retornados pela ClientCredentials propriedade da ClientBase<TChannel> classe. O código a seguir define um certificado como uma credencial em um cliente usando o 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.
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();
' 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()