Desenvolvimento - Web Services

Desenvolvendo Web Services Seguros com Kerberos

O MIT (Massachusetts Institute of Technology) criou o Kerberos, um protocolo cuja sua principal finalidade é prover um robusto mecanismo de autenticação, através de uma rede insegura...

por Bruno Spinelli Dantas



Introdução

A Internet está crescendo cada vez mais, junto com a necessidade de aplicações distribuídas. Antigamente aplicações eram executadas em ambientes isolados, onde a única ameaça era o próprio usuário da aplicação. Os tempos mudaram, hoje em dia Computadores, Celulares, Pocket Pc"s estão todos conectados, no que chamamos de World Wide Web, ou para alguns Wild Wild Web, pelo fato de ser considerado um ambiente extremamente hostil.

Esta é a motivação para que cada vez mais sejam concentrados esforços para a criação de protocolos que permitam as aplicações conviverem neste ambiente. Com esta mesma intenção o MIT (Massachusetts Institute of Technology) criou o Kerberos, um protocolo cuja sua principal finalidade é prover um robusto mecanismo de autenticação, através de uma rede insegura.

A Microsoft adotou maciçamente o uso deste protocolo a partir do Windows 2000, o utilizando como principal mecanismo de Autenticação de seus Sistemas Operacionais.

Uma outra iniciativa que prova a constante preocupação com a segurança das aplicações é a criação de padrões (Web Services Enhancements) que possibilitam a implementação de novas funcionalidades para Web Services, solucionando alguns dos principais problemas existentes na arquitetura atual, dentre estes a Segurança.

As funcionalidades que são disponibilizadas pelo WSE para o desenvolvimento de Web Services seguros são : Utilização de Tokens de Segurança, Assinatura e Encriptação de envelopes SOAP, atribuição de TimeStamps e Identificadores únicos (Nonce) para as mensagens e etc. O WSE disponibiliza dois tipos de Tokens para se implementar a autenticação em mensagens SOAP: Tokens baseados em XML (ex.: Username Tokens) e os Tokens Binários (ex.: Tokens de certificados X.509, Tokens Customizados, Token Kerberos).

Antes de demonstrar um exemplo de implementação dessa arquitetura, será detalhado um pouco mais sobre o Protocolo Kerberos para o perfeito entendimento do assunto.

A Arquitetura Kerberos

Em um típico cenário de autenticação, existe sempre um cliente, que está requisitando o uso de um determinado serviço, e uma entidade autenticadora, que contém as informações sobre todos os usuários e serviços existentes na rede.

Na arquitetura Kerberos a utilização de qualquer serviço é realizada através de Tickets. Logo para um Cliente poder utilizar determinado serviço, é necessário o mesmo ser portador de um Ticket específico para aquele Serviço.

A entidade que concede os Tickets se chama Ticket Granting Service, que na verdade é um serviço exposto na rede como outro qualquer.

Logo para obter o Ticket para utilização de um serviço na rede, é preciso se autenticar primeiramente no AS, que irá lhe fornecer um Ticket, chamado TGT - Ticket Granting Ticket, para a utilização do Ticket Granting Service, e a partir deste obter o Ticket para utilização do serviço inicialmente requisitado.

Repare que o TGS resolve o problema da autenticação repetitiva, ou seja, através dele o usuário se autentica uma única vez, e utilizando TGT, concedido pelo AS, obtém a permissão de utilização de outros serviços sem a necessidade de se autenticar repetitivamente, pois o TGS parte do princípio de que se o usuário contém o TGT ele já foi anteriormente autenticado pelo AS. O poder de reutilização do TGT tem seus prós e contras que serão detalhados posteriormente.

Mundo Real x Mundo Kerberos

Os Mecanismos de Autenticação Kerberos se parecem muito com o modelo de autenticação na vida real, com base nisso para um melhor esclarecimento, irei fazer uma analogia com um processo de autenticação típico utilizado para aquisição de um ingresso para um Evento (Show , Festa e etc...).

Antes de mais nada, para que uma pessoa possa ser considerada um cidadão, ela necessita obter uma Carteira de Identidade (RG), em uma entidade designada para tal finalidade (Ex.: Detran, Instituto Felix Pacheco e etc.). Um pré-requisito para se obter o RG é o cadastro prévio de informações (Certidão de Nascimento, Impressões Digitais e etc.). Após este processo, o novo cidadão poderá utilizar o RG para diversas finalidades que exigem sua identificação.

Seguindo nossa analogia, para comprar um ingresso para um determinado Evento, é requerido que o comprador se dirija até o local de venda e apresente sua identidade (RG). São então validadas as informações, e se as mesmas estiverem de acordo, lhe é concedido o Ingresso.

No "Mundo Kerberos", para ser um usuário de uma rede, que implemente este protocolo, é necessário primeiramente fazer um cadastro em uma entidade chamada AS (Authenticate Server). De acordo com a analogia, o mesmo faz o papel da entidade que concede a Carteira de Identidade (RG) para o cidadão. Depois do cadastro inicial ser efetuado com sucesso, o "candidato a usuário" já é considerado um usuário da rede (da mesma forma que uma pessoa de posse do RG é um cidadão), sendo assim poderá usufruir dos serviços expostos por ela.

No "Mundo Kerberos" o local de venda do ingresso é substituído por um serviço chamado TGS (Ticket Granting Service), o RG por um Ticket chamado TGT (Ticket Granting Ticket), o Ingresso por um Ticket de Autorização, e o Evento em si por um Serviço qualquer da rede.

Logo quando o portador do ingresso chega até o Evento, o mesmo não necessita mais se identificar com o RG, e sim apenas apresentar o Ingresso. Isto se dá pelo fato que a Organização do Evento pressupõe que o RG já foi apresentado no Local de Compra. Da mesma forma que de porte de um Ticket de Autorização para um determinado serviço da rede, não é necessário mais mostrar o TGT, parte-se do princípio que se você tem o Ticket de Autorização, que foi obtido através de um TGS, necessita ter o TGT.

Sendo um pouco mais detalhista, geralmente um Ingresso de um Evento tem informações de controle, tais como: uma Data correspondente ao Evento, e ainda um número único de identificação. Estas informações servem, exclusivamente, para que ninguém possa utilizar o mesmo Ingresso mais de uma vez. No "Mundo Kerberos" existem alguns Tickets que também apresentam estas informações para evitar, por exemplo, message replay. Fluxo de Autenticação Kerberos

Para detalhar o Fluxo de Autenticação Kerberos, será utilizado como exemplo um cenário comum : Um determinado cliente requisita o acesso a um servidor de emails.

Primeiramente o Cliente envia ao AS uma requisição de utilização do determinado serviço. O conteúdo desta requisição consiste, basicamente, do nome do usuário e do serviço requisitado, logo não necessita ser encriptado por não conter informações sigilosas.

O AS então, provido do nome do usuário, obtém a senha deste, respondendo para o Cliente dois pacotes de informação : o primeiro é criptografado utilizando a senha do usuário como chave de encriptação, e contém basicamente uma Chave de Sessão, que será utilizada na comunicação com o TGS, e o nome do serviço requisitado. O segundo é criptografado utilizando uma Chave do Serviço, e contém informações do usuário que o requisitou, e também a Chave de Sessão.

Quando o Cliente recebe o primeiro pacote do AS, o mesmo tenta descriptografá - lo, obtendo a senha do usuário e utilizando a mesma como chave. Se o processo de descriptação falhar é por que a senha passada pelo usuário não esta correta, logo o mesmo não tem permissão para obter as informações de determinado Ticket, não podendo assim utilizar o serviço requisitado.

O segundo pacote enviado pelo AS, é o TGT, ele é encriptado utilizando a Chave do Serviço como chave de encriptação, como já citado acima, e o cliente não tem posse da mesma e não consegue e nem precisa descriptografá-lo. O único procedimento que o mesmo deve realizar é encaminhá-lo para o TGS.

O cliente cria um novo pacote de informações chamado AUTHENTICATOR, que contém informações controle como Timestamp, e informações do usuário que requisitou o serviço. Este Ticket é encriptado com a Chave de Sessão que está contida no TGT. Logo o Servidor só irá conseguir obter as informações do AUTHENTICATOR se conseguir descriptografar apropriadamente o TGT.

O TGS primeiramente recebe o TGT, executa o processo de descriptação através de sua Chave de Serviço e obtém as informações contidas no mesmo, dentre elas a Chave de Sessão para descriptografar o AUTHENTICATOR. Depois deste processo, as informações do AUTHENTICATOR são conferidas e se as mesmas estiverem de acordo, é validado que o Cliente é realmente quem ele diz ser.

Após o TGS ter validado a autenticidade do usuário através dos Tickets, o mesmo cria e envia o Ticket necessário para utilização do serviço de email da mesma forma que o AS enviou as informações necessárias para uso do TGS, que na verdade é, como já citado, um serviço como outro qualquer na rede.

De posse do Ticket de utilização do Servidor de emails, o Cliente cria um outro AUTHENTICATOR com uma chave de sessão passada pelo TGS e os envia para o Servidor de Email. O mesmo verifica a autenticidade e permite ou não a utilização de seus serviços.

Um pouco mais sobre o AUTHENTICATOR

A principal finalidade do AUTHENTICATOR é permitir a reutilização de Tickets, prevenindo ataques como Message Replay. Logo se um Ticket for obtido na rede por um atacante e reenviado para um servidor com intenções de utilizar um serviço fingindo ser o proprietário do Ticket (Identity Spoofing), o servidor irá verificar o AUTHENTICATOR, logo se o mesmo não existir a requisição será invalidada. Nada impede do atacante obter tanto o Ticket quanto o AUTHENTICATOR na rede, e reenviá-los, porém o AUTHENTICATOR contém informações de controle como já mencionado acima.

Dentre elas um Timestamp, um tempo de expiração, e ainda um identificador único (nonce), sendo assim, quando um Servidor recebe um AUTHENTICATOR o mesmo verifica seu tempo de expiração, e ainda, se o mesmo já foi enviado recentemente através do identificador único. Compartilhamento da Chave de Sessão

O Fato da chave de sessão ser de conhecimento apenas do Cliente e do Servidor, permite a utilização da mesma para algumas funcionalidades extras como encriptação de informações compartilhadas entre os mesmos , além da possibilidade do cliente validar se o servidor que está concedendo a permissão de uso de determinado serviço esta sendo provido exatamente pelo que o mesmo requisitou, realizando assim o que é chamado de autenticação mutua, evitando que um atacante assuma a identidade de um servidor para obter informações sigilosas.

Introdução Web Service Enhancements

Microsoft Web Services Enhancements 2.0 é uma biblioteca de classes que implementa uma extensão de protocolos para Web Services, como já mencionado. A arquitetura do WSE é baseada no processamento de Mensagens SOAP através de filtros, incluindo e removendo elementos dos cabeçalhos das mensagens , bem como a transformação do corpo destas. Filtros de Entrada por exemplo lêem os cabeçalhos das mensagens, enquanto que de saída os inserem. O detalhamento desta arquitetura foge do escopo deste artigo.

Implementação do Kerberos no WSE

Agora que já foi esclarecido o funcionamento do Kerberos será demonstrado como este protocolo foi implementado através do WSE.

Como já mencionado, a autenticação é implementada no WSE através dos chamados Tokens de Segurança, mais especificamente, para o uso do Kerberos é utilizado um Token Binário. O mesmo é inserido em um envelope SOAP através do elemento <wsse:BinarySecurityToken> , e ainda são utilizados os atributos, wsse:ValueType e wsse:EncodingType para descrever o Tipo e o Enconding do Token respectivamente. Abaixo segue um exemplo de como criar um Token Kerberos utilizando o Microsoft WSE 2.0 acompanhado da requisição SOAP gerada :

[C#]

//Nome do host do serviço a ser requisitado
string targetPrincipalName = null;
targetPrincipalName = "host/" + System.Net.Dns.GetHostName();
//Crio o Token Kerberos
KerberosToken kerbToken = new KerberosToken(targetPrincipalName);
//Adiciono o Token na Coleção de Tokens da requisição SOAP
WsProxy.RequestSoapContext.Security.Tokens.Add(kerbToken);

[XML]
<?xml version="1.0" encoding="utf-8"?>
<S:Envelope xmlns:S="http://www.w3.org/2001/12/soap-envelope">
<S:Header>
 ...
<wsse:Security   
xmlns:wsse="http://schemas.xmlsoap.org/ws/2003/07/secext">
<wsse:BinarySecurityToken id="Kerberosv5ST"       
wsse:ValueType="wsse:Kerberosv5ST"                    
 wsse:EncodingType="wsse:Base64Binary">
MIIEZzCCA9CgAwIBAgIQEmtJZc0rqrKh5i...
</wsse:BinarySecurityToken>
</wsse:Security>
</S:Header>
<S:Body>
…
</S:Body>
</S:Envelope>

Para criar um Token Kerberos é necessário passar como parâmetro de seu construtor o chamado Principal Name, que nada mais é, em nosso caso, do que o nome do Servidor que contém o serviço a ser requisitado. Neste exemplo foi utilizado o próprio nome da máquina em que está sendo executado este código.

Ao criar uma instância da classe KerberosToken, a mesma obtém as credenciais do contexto de segurança em que a aplicação está sendo executada, e efetua a solicitação do Ticket para utilização do serviço (de acordo com a Arquitetura do Kerberos).

Através deste Ticket são obtidas as informações, como por exemplo a Chave de Sessão, necessárias para se criar o Token Kerberos.

Repare que estes procedimentos estão todos encapsulados na classe KerberosToken, sendo estas ações executadas de forma transparente para o desenvolvedor.

O Token Kerberos é composto basicamente pelo Ticket de Autorização do determinado Serviço, não contendo o AUTHENTICATOR. No WSE a implementação do AUTHENTICATOR ocorre através da assinatura do envelope SOAP utilizando a Chave de Sessão, que está contida no Token Kerberos.

Logo quando o Web Service receber o Envelope SOAP, o mesmo irá extrair a Chave de Sessão do Token Kerberos para então fazer a verificação da Assinatura Digital.

Como não há explicitamente um AUTHENTICATOR na mensagem é extremamente recomendável a utilização de um TimeStamp e Nonce na mensagem para que o papel do AUTHENTICATOR seja realmente exercido. Abaixo é demonstrado um exemplo de como incluir uma assinatura digital no Envelope SOAP bem como um TimeStamp e Nonce :

[C#]

//Nome do host do serviço a ser requisitado
string targetPrincipalName = null;
targetPrincipalName = "host/" + System.Net.Dns.GetHostName();
//Crio o Token Kerberos
KerberosToken kerbToken = new KerberosToken(targetPrincipalName);
//Crio um Identificador único especificando seu tamanho
Nonce nonce = new Nonce(34);
//Atribuo o Identificador ao Token
kerbToken.Id = nonce.Value;
//Adiciono o Token na Coleção de Tokens da requisição SOAP
WsProxy.RequestSoapContext.Security.Tokens.Add(kerbToken);
//Adiciono a Assinatura Digital no SOAP utilizando o Token Kerberos
WsProxy.RequestSoapContext.Security.Elements.Add(new MessageSignature(kerbToken);
//Defino um tempo de vida para minha requisição SOAP
WsProxy.RequestSoapContext.Security.Timestamp.TtlInSeconds = 60;


[XML]
<?xml version="1.0" encoding="utf-8"?>
<S:Envelope xmlns:S="http://www.w3.org/2001/12/soap-envelope">
<S:Header>
...
<wsse:Security xmlns:wsse="http://schemas.xmlsoap.org/ws/2003/07/secext">
<wsu:Timestamp wsu:Id="Timestamp-6eb8431c-92ca-4405-bc1b-76432852d3b8">
                <wsu:Created>2004-11-03T19:33:04Z</wsu:Created>
                <wsu:Expires>2004-11-03T19:34:04Z</wsu:Expires>
            </wsu:Timestamp>
<wsse:BinarySecurityToken id="Kerberosv5ST"
wsse:ValueType="wsse:Kerberosv5ST"
wsse:EncodingType="wsse:Base64Binary">
MIIEZzCCA9CgAwIBAgIQEmtJZc0rqrKh5i...
</wsse:BinarySecurityToken>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod
Algorithm="http://www.w3.org/2001/10/xml-excc14n#"/>
<ds:SignatureMethod
Algorithm="...#DES-MD5"/>
<ds:Reference>
<ds:Transforms>
<ds:Transform>
Algorithm="http://...#MyTranform"/>
<ds:Transform>
Algorithm="http://www.w3.org/2001/10/xml-excc14n#"/>
</ds:Transforms>
<ds:DigestMethod
Algorithm="...#DES-MD5"/>
<ds:DigestValue>EULddytSol...</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>
BL8jdfToEb11vXcMZNNjPOV...
</ds:SignatureValue>
<ds:KeyInfo>
<wsse:SecurityTokenReference>
<wsse:Reference URI="#Kerberosv5ST"/>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
</wsse:Security>
</S:Header>
<S:Body>
…
</S:Body>
</S:Envelope>

Encriptando Envelopes SOAP

É possível ainda encriptar requisições SOAP através do Token Kerberos. A Chave de Sessão contida no Token é utilizada para realizar a encriptação da requisição. Abaixo segue um exemplo :

[C#]
//Nome do host do serviço a ser requisitado
string targetPrincipalName = null;
targetPrincipalName = "host/" + System.Net.Dns.GetHostName();
//Crio o Token Kerberos
KerberosToken kerbToken = new KerberosToken(targetPrincipalName);
//Crio um Identificador único especificando seu tamanho
Nonce nonce = new Nonce(34);
//Atribuo o Identificador ao Token
kerbToken.Id = nonce.Value;
//Adiciono o Token na Coleção de Tokens da requisição SOAP
WsProxy.RequestSoapContext.Security.Tokens.Add(kerbToken);
//Adiciono a Assinatura Digital no SOAP utilizando o Token Kerberos
WsProxy.RequestSoapContext.Security.Elements.Add(new MessageSignature(kerbToken));
//Encripto o conteúdo (<body>) da requisição SOAP 
//utilizando o Token Kerberos
WsProxy.RequestSoapContext.Security.Elements.Add(new EncryptedData(kerbToken));
//Defino um tempo de vida para minha requisição SOAP
WsProxy.RequestSoapContext.Security.Timestamp.TtlInSeconds = 60;


[XML]
<?xml version="1.0" encoding="utf-8"?>
<S:Envelope xmlns:S="http://www.w3.org/2001/12/soap-envelope">
<S:Header>
...
<wsse:Security
xmlns:wsse="http://schemas.xmlsoap.org/ws/2003/07/secext"
xmlns:xenc="http://www.w3.org/2001/04/xmlend#">
<wsu:Timestamp wsu:Id="Timestamp-6eb8431c-92ca-4405-bc1b-76432852d3b8">
                <wsu:Created>2004-11-03T19:33:04Z</wsu:Created>
                <wsu:Expires>2004-11-03T19:34:04Z</wsu:Expires>
            </wsu:Timestamp>
<wsse:BinarySecurityToken id="Kerberosv5ST"
wsse:ValueType="Kerberosv5ST"
wsse:EncodingType="wsse:Base64Binary">
MIIEZzCCA9CgAwIBAgIQEmtJZc0rqrKh5i...
</wsse:BinarySecurityToken>
<xenc:ReferenceList>
<xenc:DataReference URI="#bodyID"/>
</xenc:ReferenceList>
</wsse:Security>
</S:Header>
<S:Body>
<xenc:EncryptedData
Id="bodyID"
Type="http://www.w3.org/2001/04/xmlenc#Element"
xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
<xenc:EncryptionMethod Algorithm="...#DES-CBC"/>
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<wsse:SecurityTokenReference>
<wsse:Reference URI="#Kerberosv5ST"/>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>d2FpbmdvbGRfE0lm4byV0...</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>
</S:Body>
</S:Envelope>

Sistemas robustos de autenticação com certeza elevam a confiabilidade de sua aplicação, porém vale lembrar que uma aplicação é tão segura quanto seu ponto mais vulnerável, logo é necessário aplicar segurança em todas as partes. A autenticação é apenas um dos fatores a serem lembrados, restando ainda outros pontos cruciais para que sua aplicação se torne o menos vulnerável possível, evitando o comprometimento de informações e ainda danos a seus usuários.

É importante fazer uma prévia Análise de Ameaças em seu Sistema, para que sejam mapeadas e classificadas as possíveis vulnerabilidades de cada funcionalidade. E lembre-se, qualquer funcionalidade de seu sistema se torna inútil se a mesma for insegura, duvida disso? Então pergunte ao usuário.

Bruno Spinelli Dantas

Bruno Spinelli Dantas - MCAD, Desenvolvedor da nTime Mobile Solutions, dedicando-se exclusivamente a Tecnologia Net, no desenvolvimento de plataformas para dispositivos móveis.