[email protected] 2PUC-RJ
Transcrição
[email protected] 2PUC-RJ
7HFQRORJLDV-DYDSDUD6HJXUDQoDGH6LVWHPDV MATHEUS CABRAL DE ARAÚJO GOIS1 HEDLENA MARIA DE ALMEIDA BEZERRA2 PAULO GONÇALVES DE BARROS3 ANDRÉ SANTOS (ORIENTADOR)3 1 IMPA – Instituto de Matemática Pura e Aplicada CEP 22460–320 Rio de Janeiro (RJ) [email protected] 2 PUC-RJ – Puntificia Universidade Católica do Rio de Janeiro CEP 22453–900 Rio de Janeiro (RJ) [email protected] 3 UFPE – Universidade Federal de Pernambuco CIn – Centro de Informática Cx. Postal 7851 – CEP 50.732–970 Recife (PE) {pgb,alms}@cin.ufpe.br 5HVXPR Segurança de sistemas é, atualmente, uma área de grande atenção no que diz respeito a desenvolvimento de sistemas comerciais. Uma vez que o uso da linguagem Java é tido como primordial no desenvolvimento desses sistemas, é importante o estudo de tecnologias Java que possam prover aspectos de segurança. O presente artigo apresenta JCA, JCE, JAAS, JSSE e -DYD &HUWLILFDWLRQ 3DWK, exemplos de tecnologias disponibilizadas pela Sun Microsystems para questões de segurança em diferentes paradigmas. 3DODYUDV&KDYHVSegurança de Sistemas, Java, API’s. ,QWURGXomR A utilização da linguagem Java no desenvolvimento de sistemas comerciais cresce principalmente devido ao fato da linguagem possuir uma série de características que facilitam e incrementam o valor agregado aos sistemas, características estas como robustez, portabilidade e extensibilidade. Entretanto, uma característica mais recentemente almejada por esses sistemas comerciais é segurança. Para tal, a Sun Microsystems [Microsystems, 2002a] disponibiliza uma série de API' s ($SSOLFDWLRQ 3URJUDPPLQJ ,QWHUIDFH) que permitem desenvolvedores incorporar funcionalidades de segurança em suas aplicações. O objetivo do presente trabalho é apresentar as tecnologias disponíveis na linguagem Java para lidar com problemas de segurança, dando uma visão geral sobre seu funcionamento, sobre suas classes, sobre como podem ser implementadas e onde podem ser encontradas. Logo abaixo, segue uma pequena lista de API' s disponibilizada pela Sun Microsystems para o desenvolvimento de sistemas com aspectos de segurança. $VSHFWRVGH6HJXUDQoDGD/LQJXDJHP-DYD Apesar de não ser uma API, é importante discutir aspectos de segurança embutidos na linguagem Java. Aspectos como checagem de índice de DUUD\V, acesso à memória e JDUEDJHFROOHFWLRQ, entre outros. -DYD&U\SWRJUDSK\$UFKLWHFWXUH-DYD&U\SWRJUDSK\([WHQVLRQ-&$-&( Biblioteca que provê um infraestrtura de acesso e desenvolvimento de criptografia. JCA/JCE definem suporte a cifragem, decifragem, concordância de chave (NH\ DJUHHPHQW), código de autenticação de mensagens (0HVVDJH$XWKHQWLFDWLRQ&RGH - MAC), KDVK e outros serviços de criptografia. -DYD$XWKHQWLFDWLRQDQG$XWKRUL]DWLRQ6HUYLFH-$$6 API que provê autenticação de usuários para autorização de tarefas. Tradicionalmente, Java 2 provê controle de acesso baseado no código-fonte (controle de acesso de acordo com o local onde o código foi originado e com a pessoa que o assinou). Entretanto, não existe a possibilidade de adicionar controle de acesso baseado em quem executa o código. JAAS incrementa a arquitetura de segurança Java 2 para suportar tal controle de acesso. -DYD6HFXUH6RFNHW([WHQVLRQ-66( JSSE é uma série de pacotes que possibilitam comunicação segura na Internet. Ela implementa os protocolos SSL (6HFXUH 6RFNHWV /D\HU) e TLS (7UDQVSRUW /D\HU 6HFXULW\) e adiciona funcionalidades para cifragem de dados, autenticação do servidor, controle de integridade, e autenticação opcional do cliente. Dessa forma, JSSE permite que desenvolvedores possam prover uma passagem segura dos dados entre cliente e servidor, em qualquer protocolo (como HTTP, Telnet, NNTP, e FTP) sobre TCP/IP. -DYD&HUWLILFDWLRQ3DWK$3, API provendo classes que permitem desenvolver e validar certificados digitais, um requisito importante de uma Infraestrutura de Chave Pública. A construção e validação de certification path é uma parte importante de muitos protocolos padrões de segurança tais como SSL/TLS, S/MIME, e IPSEC. A API Java Certification Path provê um conjunto de classes e interfaces para desenvolvedores que precisam integrar estas funcionalidades dentro de suas aplicações. Antes de entrar em detalhes sobre cada uma das tecnologias supracitadas, uma breve revisão de conceitos será apresentada abaixo: • • • • +DVK: é um pequeno trecho de texto gerado para representar um texto maior. A idéia é que não existam textos que gerem mesmas KDVKHV, de forma que uma KDVK seja capaz de validar a integridade de uma mensagem.É também conhecido como 0HVVDJHGLJHVW; )XQomRGHKDVK: uma função que transforma qualquer texto em uma VWULQJ de tamanho padrão. É de via única porque é praticamente impossível achar o texto original a partir dessa VWULQJ; &KDYH : uma senha ou tabela de senhas utilizadas para codificar e decodificar textos e mensagens; &ULSWRJUDILD VLPpWULFD : cifragem de texto onde a chave de codificação é a mesma utilizada na decodificação; • • &ULSWRJUDILD DVVLPpWULFD: cifragem de texto onde a chave de codificação é diferente da utilizada na decodificação. Existem chaves públicas, de sabedoria de qualquer um e chaves privadas, particulares a cada um. Quando um remetente quer mandar uma mensagem para alguém, cifra-a com a chave pública desse receptor. Ao receber a mensagem, o receptor utiliza sua chave privada para decifrar o texto. Esse sistema pode ser utilizado também na autenticação de mensagens. Um remetente, para garantir que é ele quem está enviando a mensagem, cifra a mensagem enviada com sua chave privada e a anexa à mensagem original. O receptor, então, para certificar-se de que a mensagem foi realmente enviada por quem ele esperava, pega a chave pública desse alguém, decifra o texto codificado, anexado com a mensagem, e compara-o com o original. Vendo que o texto decifrado é igual ao original, o receptor tem certeza da autenticidade do remetente. O interessante desse sistema é que é impossível deduzir a chave privada de alguém com base na chave pública, no texto original e no texto cifrado; $VVLQDWXUD: consiste no texto cifrado e anexado à mensagem descrito no exemplo descrito acima (em criptografia assimétrica), em que o remetente anexa à mensagem um texto que só ele pode ter gerado com sua chave privada e capaz de identificar que foi realmente ele quem enviou a mensagem; • $XWHQWLFDomR • &RQWUROH GH DFHVVR : consiste no processo de verificar e inserir assinaturas em mensagens; : consiste na restrição de acesso de uma máquina, diretório ou arquivo a uma pessoa ou grupo específico de pessoas; • $OJRULWPR GH )HLVWHO: algoritmo de cifragem de mensagens em blocos que consiste em dividir as mensagens em duas partes. Uma delas é modificada, quando é aplicado a si um XOR com uma função da outra metade. As partes da mensagem são invertidas e o processo é repetido por um número finito de vezes. Na função aplicada, a chave entra como parâmetro. A mesma pode variar ou não de rodada em rodada. O restante do documento está dividido da seguinte maneira. A próxima seção apresenta aspectos da segurança da própria linguagem Java. A seção 3 apresenta as arquiteturas JCA e JCE. Uma descrição do JAAS é apresentada na seção 4. As seções 5 e 6 apresentam o JSSE e o -DYD&HUWLILFDWLRQ3DWK, respectivamente. Por fim, na seção 7, serão traçadas algumas conclusões sobre o presente trabalho. $VSHFWRVGH6HJXUDQoDGD/LQJXDJHP-DYD Apesar do reforço com políticas de proteção ser parte substancial da segurança, durante a execução do código, propriedades de segurança devem ser pensadas desde a geração do E\WHFRGH. Uma linguagem fortemente tipada, como Java, que é reforçada pelo compilador e checada pelo ambiente em tempo de execução, provê uma maior proteção para ambientes de maneira geral. Em sistemas mais antigos, grande parte das falhas consistia na possibilidade dos EXIIHUV serem extrapolados facilmente ou de áreas de memória serem acessadas deliberadamente. Essas situações são causadas em parte pela vulnerabilidade da segurança nos tipos e pelo reforço inadequado na execução do ambiente. A segurança em Java se manifesta nos seguintes modos: proteção construída dentro da linguagem, flexibilidade de APIs para ambientes seguros, e proteção contra acidentes ou ataques maliciosos à linguagem e à plataforma. O programador só precisa implementar algo realmente quando a segurança de Java certifica-se de que as especificações para a linguagem e para a máquina virtual (VM) sejam seguidas. Apesar das verificações de segurança reforçadas pelo compilador, a VM deve ainda poder tratar de E\WHFRGH defeituoso, se gerado acidental ou maliciosamente. Como a segurança da linguagem é inerente ao projeto da linguagem, o projeto de Java teve influência forte das linguagens de programação C e C++, tentando lidar com as principais causas de problemas de segurança nessas linguagens. Conseqüentemente, o compilador Java gera avisos para variáveis não inicializadas. A própria linguagem é fortemente tipada, com muitas construções não-seguras omitidas ou modificadas; por exemplo, acessos a DUUD\V são feitos com uma checagem de índice. Além disso, pela desalocação da memória ser responsabilidade do JDUEDJH FROOHFWRU ao invés do programador, Java evita muitos erros de programação que ocorrem em linguagens comuns como C e C++ causados na tentativa do programador de fazer essa tarefa. Outro fator importante é que o próprio compilador Java permite o tratamento de exceções, evitando assim possíveis brechas dos programas. Essa abordagem de tratamento e solução de erros potenciais pode não ter implicações diretas na segurança. Contudo, um erro não gerenciado pode levar a um comportamento imprevisível, que do ponto de vista de segurança, deve ser evitado. -DYD&U\SWRJUDSK\$UFKLWHFWXUH-DYD&U\SWRJUDSK\([WHQVLRQ Apesar de estarem fortemente ligadas, JCA e JCE possuem papéis diferentes no que diz respeito à criptografia em Java. Para deixar isso mais claro ao leitor, iremos entrar em detalhes sobre cada um desses papéis. JCA (-DYD &U\SWRJUDSK\ $UFKLWHFWXUH) é uma arquitetura ou IUDPHZRUN de acesso e desenvolvimento de funcionalidades criptográficas. No JDK 1.1, o JCA incluía API's para assinaturas digitais e PHVVDJH GLJHVWV (KDVK). O JCA foi amplamente expandido e atualizado, por exemplo, no que diz respeito à infra-estrutura de manipulação de certificados a fim de suportar certificados X.509 v3. Segundo [Microsystems, 2002b], o JCA foi desenvolvido a partir dos seguintes princípios: ,QGHSHQGrQFLDGHLPSOHPHQWDomR É obtida através da definição de uma arquitetura baseada em provedores: &U\SWRJUDSKLF6HUYLFH3URYLGHU (ou simplesmente provedores), conceito esse que será explicado mais adiante. ,QWHURSHUDELOLGDGHGHLPSOHPHQWDomR Significa que várias implementações podem trabalhar conjuntamente sem nenhuma carga ou dificuldade para o desenvolvedor. ,QGHSHQGrQFLDGHDOJRULWPR É obtida através da definição de tipos de serviços criptográficos (HQJLQHV), e definindo classes contendo as funcionalidades desses serviços. Exemplos dessas classes são: MessageDigest, Signature, entre outros. ([WHQVLELOLGDGHGHDOJRULWPR Significa que novos algoritmos podem ser facilmente incluídos na arquitetura. O Conceito de CSP (&U\SWRJUDSKLF 6HUYLFH 3URYLGHU) ou simplesmente provedor é de suma importância para o bom entendimento do JCA, uma vez que o mesmo é totalmente baseado nesses componentes. Provedor é um pacote ou um conjunto de pacotes que implementam um ou mais serviços de criptografia, como algoritmos de assinatura digital, algoritmos de KDVK, entre outros. Como exemplo, um programa pode necessitar de um certo tipo de objeto (como um MessageDigest, por exemplo) implementando um determinado serviço (como o algoritmo de KDVK SHA-1) e obter a implementação de um de seus provedores instalados. Se desejado, o programa pode pedir a implementação de um provedor específico. Atualmente, os serviços suportados pelo JCA são: assinaturas digitais, PHVVDJHGLJHVWV (KDVK), geração de chaves, fábricas de chaves, criação e manutenção segura de chaves (NH\VWRUHV), manipulação de parâmetros de algoritmos, geração de parâmetros de algoritmos, fábricas de certificados, além de algoritmos de geração de números aleatórios. O JRE da Sun Microsystems [Microsystems, 2002a] já possui um provedor padrão, chamado "SUN". Tal provedor implementa uma série de serviços como: implementação do DSA para assinatura digital, implementações do MD5 e do SHA-1 para PHVVDJHGLJHVWV, entre outros. JCE (-DYD &U\SWRJUDSK\ ([WHQVLRQ) [Microsystems, 2002c] é uma expansão do JCA a fim de incluir API's de cifragem, decifragem, trocas de chaves e MACs. Baseia-se na mesma arquitetura orientada a provedores do JCA. Além disso, o JRE da Sun Microsystems já possui um provedor padrão do JCE, chamado "SunJCE". As arquiteturas JCA e JCE podem ser vistas na Figura 1 e são amplamente detalhadas em [Microsystems, 2002b] e [Microsystems, 2002c]. )LJXUD Java Cryptography Extension. (Fonte: [Microsystems, 2002a]) $UTXLWHWXUD-&$-&( Nessa seção serão descritos os pacotes, classes e interfaces principais do JCA e JCE. As classes e interfaces principais do JCA se encontram nos pacotes java.security, java.security.spec e java.security.interfaces e são elas: Provider, Security, MessageDigest, KeyPairGenerator, SecureRandom e Signature. Para um estudo mais detalhado dessas e de outras classes e interfaces, o leitor pode consultar [Microsystems, 2002b]. Abaixo uma pequena descrição de cada uma dessas classes. • • • 3URYLGHU Classe responsável por referenciar um pacote ou conjunto de pacotes que implementam um subconjunto dos aspectos criptográficos. Deve ser adicionado como provedor através do método addProvider(Provider provider) da classe Security. 6HFXULW\ Classe que gerencia vários provedores e propriedades de segurança do sistema. Essa classe só possui métodos estáticos e não pode ser instanciada. Essa classe é responsável por fornecer funcionalidade criptográfica a KDVKHV ou PHVVDJH seguros, como MD5 e SHA1 [Schneier, 1995]. O método getInstance(String hash) retorna uma instância dessa classe para o algoritmo passado como parâmetro. 0HVVDJH'LJHVW GLJHVWV • • • .H\3DLU*HQHUDWRU Classe que gera pares de chaves públicas e getInstance(String algoritmo) para criar uma instância da classe. privadas. Utiliza o método 6HFXUH5DQGRP Classe que é responsável por fornecer funcionalidade à geração de números aleatórios com “segurança”, ou seja, cujo período seja bastante elevado. Utiliza o método getInstance(String algoritmo) para criar uma instancia da classe. 6LJQDWXUH Classe que é responsável por fornecer funcionalidade algoritmos de assinatura digital como DAS ou RSA com MD5 [Schneier, 1995]. Utiliza o método getInstance(String algoritmo, String provedor) para criar uma instância da classe do algoritmo e do provedor especificados. As classes e interfaces principais do JCE se encontram nos pacotes javax.crypto, javax.crypto.spec e javax.crypto.interfaces e são elas: Cipher, Mac, KeyGenerator, KeyAgreement e SealedObject. Para um estudo mais detalhado dessas e de outras classes e interfaces, o leitor pode consultar [Microsystems, 2002c]. Abaixo uma pequena descrição de cada uma dessas classes. • • • • • &LSKHU Determina a funcionalidade de cifradores criptográficos usados na cifragem e decifragem de dados. O método estático getInstance() é usado para criar uma instância dessa classe. 0DF Determina a funcionalidade de Message Authentication Code. Utiliza o método estático getInstance() para criar uma instância dessa classe. .H\*HQHUDWRUGera chaves secretas para algoritmos de criptografia simétricos. Os métodos getInstance() e generateKey() são usados, respectivamente, para obter uma instância da classe e gerar a chave secreta. Essa classe se diferencia da classe KeyPairGenerator, uma vez que essa última é para algoritmos assimétricos enquanto a KeyGenerator é para algoritmos simétricos. .H\$JUHHPHQWUtiliza o método doPhase() para a concordância de chaves em fases, seguido do método generateSecret() para o cálculo da chave compartilhada uma vez que as fases foram completadas. 6HDOHG2EMHFWClasse que permite o programador criar um objeto e proteger sua confidencialidade através de um algoritmo criptográfico. Utiliza o método getObject(Cipher cipher) para retornar o objeto original caso a senha (pertencente ao objeto cipher) seja válida. 0RGHORGH3URJUDPDomR-&$-&( Nessa seção serão apresentados três exemplos de programação utilizando a API JCA/JCE. O primeiro exemplo trata da geração do KDVK de uma mensagem, utilizando o algoritmo MD5 [Schneier, 1995]. O segundo exemplo trata da cifragem da mesma mensagem através do algoritmo %ORZILVK [Schneier, 1995]. O terceiro exemplo mostra o processo de cifragem e decifragem de uma mensagem usando o algoritmo DES, utilizando o modo ECB ((OHFWURQLF &RGHERRN) e o PKCS5 como “SDGGLQJ” [Schneier, 1995], [Stinson, 2002]. É importante observar que o primeiro exemplo não adiciona qualquer provedor uma vez que a classe MessageDigest já se encontra no pacote java.security do JRE da Sun Mycrosystems [Microsystems, 2002a]. 3.2.1 MD5 public class Hash { public static void main(String[] args) throws Exception { /* Mensagem original*/ String message = "Aqui fica a mensagem"; /* Cria o message digest */ MessageDigest md5 = MessageDigest.getInstance("MD5"); /* calcula o hash da mensagem */ byte[] hash = md5.digest(message.getBytes()); } } 3.2.2 Blowfish public class BlowfishKey { public static void main(String[] args) throws Exception { /* Mensagem */ String message = "Aqui fica a mensagem"; /* Adiciona o provedor */ Provider sunJce = new com.sun.crypto.provider.SunJCE(); Security.addProvider(sunJce); /* Gera a chave */ KeyGenerator kgen = KeyGenerator.getInstance("Blowfish"); SecretKey skey = kgen.generateKey(); byte[] raw = skey.getEncoded(); /* Cria e inicializa o Cipher */ SecretKeySpec skeySpec = new SecretKeySpec(raw, "Blowfish"); Cipher cipher = Cipher.getInstance("Blowfish"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec); /* cifra a mensagem */ byte[] encrypted = cipher.doFinal(message.getBytes()); } } 3.2.3 DES public class DES { public static void main(String[] args) throws Exception { /* Mensagem */ String message = "Aqui fica a mensagem"; /* Adiciona o provedor */ Provider sunJce = new com.sun.crypto.provider.SunJCE(); Security.addProvider(sunJce); /* Gera a chave */ KeyGenerator kgen = KeyGenerator.getInstance("DES"); SecretKey desKey = kgen.generateKey(); /* Cria e inicializa o Cipher */ Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, desKey); /* cifra a mensagem */ byte[] cyphertext = cipher.doFinal(message.getBytes()); /* Inicializado o cipher para o modo de decifragem */ cipher.init(Cipher.DECRYPT_MODE, desKey) /* decifra a mensagem */ byte[] message2 = cipher.doFinal(cyphertext); /* As mensagens message e message2 são identicas aqui */ } } -DYD$XWKHQWLFDWLRQDQG$XWKRUL]DWLRQ6HUYLFH Java 2 provê controle de acesso baseados no código fonte, ou seja, de onde o código se origina (URL) e em quem foi o responsável pelo código (certificados). Contudo, ele não permite o controle de acesso baseado em quem executa o código. JAAS foi criada com a finalidade de fornecer esse controle à arquitetura Java 2, como ilustrado na Figura 2 e amplamente detalhado em [Microsystems, 2002d]. O sistema de autenticação de JAAS é feito em forma de componentes encaixáveis, implementando uma versão em Java do padrão de estrutura PAM (3OXJJDEOH $XWKHQWLFDWLRQ 0RGXOH) [Samar, 2002]. Isso permite que aplicações executem independentemente da tecnologia de autenticação sendo utilizada no sistema como um todo, como ilustrado na Figura 3. Dessa forma, essa tecnologia pode ser modificada ou substituída sem necessidade de modificação na aplicação. )LJXUD Estrutura de autenticação baseada no usuário. (Fonte: [Microsystems, 2002a]) )LJXUD Autenticação baseada em componentes (Fonte: [Microsystems, 2002a]) JAAS era um pacote opcional para o Java 2 SDK Standard Edition (J2SDK) nas versões 1.3.x. Porém, atualmente, o JAAS já se encontra integrado no J2SDK versão 1.4, aprimorando a plataforma Java 2 com ferramentas para autenticação e controle de acesso para usuários. $UTXLWHWXUD-$$6 Nessa seção serão descritos os pacotes, classes e interfaces principais do JAAS. As classes e interfaces principais do JAAS se encontram nos pacotes javax.security.auth, javax.security.auth.callback, javax.security.auth.login, javax.security.auth.spi e são elas: Subject, Principal, Credential, LoginContext, LoginModule, CallbackHandler, Callback, Policy e AuthPermission. Para um estudo mais detalhado dessas e de outras classes e interfaces, o leitor pode consultar [Microsystems, 2002d], [Microsystems, 2002f] e [Microsystems, 2002g]. Abaixo, uma pequena descrição de cada uma dessas classes. • 6XEMHFW Representa as informações de uma única entidade, como uma pessoa ou um serviço. Essas informações incluem sua identidade, bem como seus atributos relacionados à segurança como senhas e chaves criptográficas. Um Subject pode possuir muitos Principals. Por exemplo, uma pessoa pode possuir o Principal nome (“Paulo Gonçalves”) e o Principal cpf (“123-45-6789”) fazendo-se distinguir de outras entidades (Subject). • 3ULQFLSDO Consiste numa interface que representa a abstração de um identificador principal, utilizada para representar qualquer tipo de entidade, seja ela uma pessoa, corporação ou um número identificador para acesso (login ID). Assemelha-se à chave primária para uma tabela de banco de dados. • &UHGHQWLDO Qualquer classe pode representar uma credencial, contanto que implemente duas interfaces relacionadas a credenciais: Refreshable e Destroyable. A interface Refreshable permite que a credencial se atualize (refresh), como por exemplo, uma credencial com tempo restrito pode implementar essa interface a fim de permitir que seus usuários atualizem o período de vida da credencial para que a mesma continue válida. Já a interface Destroyable permite a destruição do conteúdo da credencial. • /RJLQ&RQWH[W Descreve os métodos básicos para autenticar Subjects e provê um modo de desenvolver aplicações que são independentes de tecnologia de autenticação utilizada fazendo uso de um arquivo de configuração. Esse arquivo especifica a tecnologia de autenticação, ou LoginModule, acoplada ao sistema e que será utilizada pela aplicação em questão. A autenticação em si ocorre com a chamada do método de login(). • /RJLQ0RGXOH Descreve a interface implementada pelos provedores de tecnologias de autenticação. São encaixados como base para as aplicações, provendo serviços de um tipo de autenticação específica. Por exemplo, um tipo de LoginModule pode fornecer autenticação baseada no ORJLQ/senha, enquanto que outro LoginModule pode interagir com hardwares especiais e fornecer autenticação baseada em VPDUW FDUGV ou dispositivos biométricos. Os principais métodos dessa classe são: login(), commit(), abort()e logout(). • &DOOEDFN+DQGOHU Classe responsável por se comunicar com o usuário e obter informações de autenticação. Normalmente chamada pelos LoginModules, passa as mesmas informações de cDOOEDFN, como NameCallback e PasswordCallback, permitindo ou não a autenticação do usuário. • &DOOEDFN Como exemplificado anteriormente, essa classe é responsável por permitir que serviços interajam com aplicações para recuperação de informações (nome, senha, etc.) ou também para apresentação das mesmas (como mensagens de erro ou alerta). • 3ROLF\ Classe abstrata responsável por representar, através de arquivos de configuração, a política de controle de acesso de todo o sistema. • $XWK3HUPLVVLRQ Classe que encapsula as permissões básicas necessárias para o JAAS. 0RGHORGH3URJUDPDomR-$$6 Nessa seção serão apresentados dois exemplos de programação utilizando a API JAAS. O primeiro exemplo trata da autenticação baseada em uma política chamada VDPSOH e um CallbackHandler definido pelo sistema chamado MyCallbackhandler, onde é feita a leitura do ORJLQ e senha do usuário. Além disso, esse exemplo também trata, no final, a autorização para fazer uma ação (SampleAction) uma vez que o usuário já foi autenticado. O segundo exemplo mostra arquivos de configuração do ORJLQ, autenticação e autorização utilizados no primeiro exemplo. Para maiores informações sobre esses e outros exemplos, o leitor pode consultar [Microsystems, 2002d], [Microsystems, 2002f], [Microsystems, 2002g] e [Srinivas, 2002]. 4.2.1 Autenticação public class SampleAcn { public static void main(String[] args) { LoginContext lc = null; try { /* Cria o LoginContext baseado em um CallBack definido pelo sistema chamado MyCallbackHandler */ lc = new LoginContext("Sample", new MyCallbackHandler()); } catch (LoginException le) { System.err.println("Cannot create LoginContext. " + le.getMessage()); System.exit(-1); } catch (SecurityException se) { System.err.println("Cannot create LoginContext. " + se.getMessage()); System.exit(-1); } try { /* Tenta fazer o login */ lc.login(); // if we return with no exception, authentication succeeded } catch (LoginException le) { System.err.println("Authentication failed:"); System.err.println(" " + le.getMessage()); } /* Autenticacao verificada */ System.out.println("Authentication succeeded!"); Subject mySubject = lc.getSubject(); /* Mostra quantas credenciais o usuario possui */ System.out.println("User has " + mySubject.getPublicCredentials().size() + " Public Credential(s)"); /* Tenta executar uma SampleAction como o Subject autenticado */ PrivilegedAction action = new SampleAction(); Subject.doAsPrivileged(mySubject, action, null); System.exit(0); } } Exemplo de Arquivos de Configuração do Login, Autenticação e Autorização /* Login */ Sample { sample.module.SampleLoginModule required debug=true; }; /* Autenticação */ grant codebase "file:./SampleAcn.jar" { permission javax.security.auth.AuthPermission "createLoginContext.Sample"; }; /* Autorização */ grantcodebase "file:./SampleAction.jar", Principal sample.principal.SamplePrincipal "testUser" { permission java.util.PropertyPermission "java.home", "read"; permission java.util.PropertyPermission "user.home", "read"; permission java.io.FilePermission "foo.txt", "read"; }; -DYD6HFXUH6RFNHW([WHQVLRQ Dados viajam através da rede e podem ser facilmente acessados por qualquer pessoa que não é o destinatário, mas que tem conhecimento em como obtê-los da rede. Quando, nos dados, estão inclusos informações confidencias/pessoais, como senhas e número de cartão de crédito, vários passos devem ser feitos a fim de tornar os dados ininteligíveis para esses curiosos não autorizados a vê-los. Além disso, é importante checar a integridade dos dados através da verificação de alterações no mesmo (intencionais ou não) durante sua transmissão. Os protocolos 6HFXUH 6RFNHWV /D\HU e 7UDQVSRUW/D\HU6HFXULW\ foram desenvolvidos para ajudar a proteger e verificar integridade dos dados transportados através da rede. -DYD6HFXUH6RFNHW([WHQVLRQ (JSSE) é uma API que permite comunicação segura na internet. Basicamente, JSSE provê um IUDPHZRUN e uma implementação para SSL e TLS. Além disso, a API inclui: funcionalidades de cifragem de dados, de autenticação do servidor, de verificação de integridade da mensagem e de autenticação do cliente. Através dessa API, desenvolvedores podem transmitir mensagens de maneira segura entre programas clientes e programas servidores, utilizando qualquer protocolo de aplicação (HTTP, Telnet, FTP) sobre TCP/IP. Na comunicação através de JSSE, vários algoritmos complexos de cifragem/decifragem, autenticação e negociação (KDQGVKDNLQJ) ocorrem de maneira transparente para o desenvolvedor, minimizando o risco de eventuais vulnerabilidades na implementação do código. Tal abordagem também simplifica o desenvolvimento da aplicação, pois fornece, a esses desenvolvedores, total abstração do processo e permite que módulos sejam facilmente integrados em suas aplicações e invocados sem necessidade de implementação. Diferentemente de JCE, o acordo de chave (NH\DJUHHPHQW) e configurações dos FRGLILFDGRUHV (FLSKHUV) ocorre de maneira transparente sobre SSL. Além disso, JCE opera em estruturas de dados locais enquanto que JSSE possui um nível de abstração diferente, aplicando cifragem/decifragem de maneira transparente no tráfego da rede. Por outro lado, JSSE utilizou a arquitetura baseada nos princípios encontrados no IUDPHZRUN JCA, o qual fornece uma arquitetura de provedores que permitem independência de implementação e, quando possível, independência de algoritmo. A API JSSE possui um provedor chamado "SunJSSE" que vem pré-instalado e pré-registrado no JCA. Maiores informações sobre funcionalidades inclusas nesse provedor serão descritas mais abaixo e podem ser consultadas em [Zukowski, 2002] e [Microsystems, 2002e]. $UTXLWHWXUD-66( Nessa seção serão descritos os pacotes, classes e interfaces principais do JSSE. As classes e interfaces principais do JSSE se encontram nos pacotes javax.net, javax.net.ssl e javax.security.cert e são elas: SSLSocket, SSLServerSocket, SocketFactory, ServerSocketFactory, SSLSocketFactory e SSLServerFactorySubject. Para um estudo mais detalhado dessas e de outras classes e interfaces, o leitor pode consultar [Microsystems, 2002e] e [Srinivas, 2002]. Abaixo uma pequena descrição de cada uma dessas classes. • 66/6RFNHW Essa classe é uma subclasse do VRFNHW padrão de Java (java.net.Socket). Ela suporta todos os métodos de VRFNHW e adiciona métodos específicos para VRFNHWV seguros. Instancias dessa classe são obtidas através da classe SocketFactory. • 66/6HUYHU6RFNHW Essa classe é análoga a SSLSocket, mas é usada na criação de VRFNHWV servidores. Analogamente, instâncias dessa classe são obtidas através da classe ServerSocketFactory. • 6RFNHW)DFWRU\ Classe abstrata responsável pela criação de (String host, int port) para criar um VRFNHW seguro. • VRFNHWV . Utiliza o método createSocket 6HUYHU6RFNHW)DFWRU\ Classe abstrata análoga a SocketFactory, mas é usada na criação de servidores de seguros (SSLServerSocket). Utiliza o método createServerSocket(int port) para criar um servidor seguro. VRFNHWV • 66/6RFNHW)DFWRU\ • 66/6HUYHU)DFWRU\6XEMHFW Classe que é uma implementação concreta da classe SocketFactory. Classe que é uma implementação concreta da classe SocketServerFactory. 0RGHORGH3URJUDPDomR-66( Nessa seção será apresentado um exemplo de programação utilizando a API JSSE. Nesse exemplo, são apresentados 4 trechos de código onde é demonstrada a facilidade da conversão de uma aplicação utilizando VRFNHWV não seguros para VRFNHWV seguros através da API JSSE. Para maiores informações sobre esses e outros exemplos, o leitor pode consultar [Microsystems, 2002e] e [Srinivas, 2002]. 5.2.1 Conversão de Sockets inseguros para Sockets seguros /* Servidor inseguro */ public class UnsecureServer{ public static void main(String[] args){ ... ServerSocket s; int port = availablePortNumber; try { /* Cria o servidor */ s = new ServerSocket(port); Socket c = s.accept(); OutputStream out = c.getOutputStream(); InputStream in = c.getInputStream(); /* Envia e recebe mensagens para cliente através do OutputStream e do InputStream */ } catch(IOException e) { // Trata o erro } } } /* Servidor seguro */ public class SecureServer{ public static void main(String[] args){ ... 66/6HUYHU6RFNHW s; int port = availablePortNumber; try { 66/6HUYHU6RFNHW)DFWRU\VVO6UY)DFW 66/6HUYHU6RFNHW)DFWRU\ 66/6HUYHU6RFNHW)DFWRU\JHW'HIDXOW /* Cria o servidor */ V 66/6HUYHU6RFNHWVVO6UY)DFWFUHDWH6HUYHU6RFNHWSRUW 66/6RFNHWF 66/6RFNHWVDFFHSW OutputStream out = c.getOutputStream(); InputStream in = c.getInputStream(); /* Envia e recebe mensagens para cliente através do OutputStream e do InputStream */ } catch(IOException e) { // Trata o erro } } } /* Cliente inseguro */ public class UnsecureClient{ public static void main(String[] args){ ... int port = availablePortNumber; String host = "hostname"; try { /* Cria o cliente */ Socket s = new Socket(host, port); OutputStream out = c.getOutputStream(); InputStream in = c.getInputStream(); /* Envia e recebe mensagens para servidor através do OutputStream e do InputStream */ } catch(IOException e) { // Trata o erro } } } /* Cliente seguro */ public class SecureClient{ public static void main(String[] args){ ... int port = availablePortNumber; String host = "hostname"; try { 6/6RFNHW)DFWRU\VVO)DFW 66/6RFNHW)DFWRU\66/6RFNHW)DFWRU\JHW'HIDXOW /* Cria o cliente */ 66/6RFNHWV 66/6RFNHWVVO)DFWFUHDWH6RFNHWKRVWSRUW OutputStream out = c.getOutputStream(); InputStream in = c.getInputStream(); /* Envia e recebe mensagens para servidor através do OutputStream e do InputStream */ } catch(IOException e) { // Trata o erro } } } -DYD&HUWLILFDWLRQ3DWK Muitos dos mecanismos por trás das aplicações modernas e de segurança de redes são baseadas num tipo de criptografia conhecida como criptografia de chave pública. As chaves pública e privada provêem mecanismos para que uma entidade possa estabelecer, e outras possam verificar, sua identidade online (um importante ingrediente para transações confiáveis). Infelizmente, a criptografia de chave-pública é efetivada somente se a chave privada de uma entidade A, por exemplo, é secreta. Se outra entidade hostil B obtém uma cópia da chave privada pertencente à A, esta entidade pode se passar por A eletronicamente. No melhor caso, se uma entidade perder sua chave privada, ela perde a capacidade de provar sua identidade eletronicamente. Um certificado de chave pública é uma ligação entre a chave pública e uma identidade, que é digitalmente assinada pela chave privada de uma outra entidade, freqüentemente chamada de Autoridade Certificadora (AC). Se um usuário não tem uma cópia confiável da chave pública da AC que certificou uma chave pública de uma entidade, então uma outra verificação de certificado de chave pública para este AC é necessária. Esta lógica pode ser aplicada recursivamente, até que uma cadeia de certificados (FHUWLILFDWLRQSDWK) seja descoberta de um AC confiável até a autoridade em questão (geralmente chamado de entidade-final). A AC mais confiável é geralmente especificada por um certificado emitido por um AC que o usuário confia diretamente. Em geral, um FHUWLILFDWLRQSDWK é uma lista ordenada de certificados, geralmente formados pela chave pública da entidade final e certificados adicionais. A construção e validação de FHUWLILFDWLRQSDWK é uma parte importante de muitos protocolos padrões de segurança tais como SSL/TLS, S/MIME, e IPSEC. A API -DYD &HUWLILFDWLRQ 3DWK provê um conjunto de classes e interfaces para desenvolvedores que precisam integrar estas funcionalidades dentro de suas aplicações. Esta API beneficia dois tipos de desenvolvedores: aqueles que escrevem implementações de provedores de serviços para a construção de um FHUWLILFDWLRQ SDWK específico ou validação do algoritmo e aqueles que precisam acessar algoritmos padrões para criação e validação de FHUWLILFDWLRQ SDWKV independentes da maneira como foram implementados. $UTXLWHWXUD-DYD&HUWLILFDWLRQ3DWK Nessa seção serão descritos os pacotes, classes e interfaces principais da API -DYD&HUWLILFDWLRQ3DWK. As classes e interfaces principais do -DYD&HUWLILFDWLRQ3DWK se encontram no pacote java.security.cert e são elas: CertPath, CertificateFactory, CertPathParameters, CertPathValidator, CertPathValidatorResult, CertPathBuilder, CertPathBuilderResult, CertStore, CertStoreParameters, CertSelector e CRLSelector, agrupadas em quatro categorias (básico, validação, construção e armazenamento). Para um estudo mais detalhado dessas e de outras classes e interfaces, o leitor pode consultar [Mullan, 2002], [Sundsted, 2002] e [Srinivas, 2002]. Abaixo, uma pequena descrição de cada uma dessas classes. 6.1.1 • • • &HUW3DWK Essa classe abstrata define as funcionalidades de todos os objetos do certification path. Vários tipos de certification path podem ser implementados simplesmente herdando/estendendo essa classe. Instâncias dessa classe são obtidas através da classe CertificateFactory. &HUWLILFDWH)DFWRU\ Em versões anteriores a J2SDK 1.4, essa classe gerava apenas objetos do tipo Certificate e CRL. Na versão J2SDK 1.4 essa classe também gera objetos CertPath. É utilizada quando um certification path já foi descoberto e necessita então instanciar um objeto CertPath. Possui generateCertPath(InputStream input) como método principal. &HUW3DWK3DUDPHWHUV Representa transparentemente um conjunto de parâmetros utilizados em um algoritmo particular de criação ou validação do certification path. Seu propósito principal é agrupar todos os parâmetros do certification path. 6.1.2 • • • Classes e interfaces de validação &HUW3DWK9DOLGDWRUClasse responsável pela validação de um certification path. É instanciada através do método estático getInstance(String algorithm). Executa a validação através do método validate(CertPath certPath, CertPathParameters params) retornando um objeto do tipo CertPathValidatorResult. &HUW3DWK9DOLGDWRU5HVXOWInterface que representa de maneira transparente os resultados bem sucedidos ou saídas do algoritmo de validação do certification path. Seu propósito principal é o de agrupar todos os resultados da validação. 6.1.3 • Classes e interfaces básicas Classes e interfaces de construção &HUW3DWK%XLOGHU Classe responsável pela criação de um certification path. É instanciada através do método estático getInstance(String algorithm). Executa a criação através do método build(CertPathParameters pars) retornando um objeto do tipo CertPathValidatorResult. &HUW3DWK%XLOGHU5HVXOW Interface que representa de maneira transparente os resultados bem sucedidos ou saídas do algoritmo de criação do certification path. Seu propósito principal é o de agrupar todos os resultados da criação. Utiliza o método getCertPath() para retornar o CertPath, ou seja, o certification path. 6.1.4 • Classes e interfaces de armazenamento Classe responsável por fornecer funcionalidade de repositório a certificados e CRL (&HUWLILFDWH /LVW É instanciada através do método estático getInstance(...). Utiliza os métodos getCertificates(CertSelector selector) e getCRLs(CRLSelector selector) para retornar, respectivamente, uma coleção de certificados e CRL. &HUW6WRUH 5HYRFDWLRQ • • • &HUW6WRUH3DUDPHWHUV Representa transparentemente um conjunto de parâmetros utilizados em um CertStore particular. Seu propósito principal é agrupar todos os parâmetros de armazenamento. &HUW6HOHFWRU Interface que representa um conjunto de critérios para filtrar certificados a partir de uma coleção maior de certificados. Utiliza o método match(Certificate cert) para verificar se o argumento satisfaz os critérios, retornando “verdadeiro” (true) nesse caso. &5/6HOHFWRUInterface que representa um conjunto de critérios para filtrar CRLs a partir de uma coleção maior de CRLs. Utiliza o método match(CRL crl) para verificar se o argumento satisfaz os critérios, retornando “verdadeiro” (true) nesse caso. &RQFOXVmR É visível o crescimento de utilização da linguagem Java para o desenvolvimento de aplicações comerciais que necessitem de algum aspecto de segurança. Esse artigo apresenta uma série de API's que podem prover tais aspectos. Foram apresentadas e discutidas API's de criptografia (JCA/JCE), autenticação e autorização (JAAS), comunicação segura (JSSE) e certificação digital (-DYD&HUWLILFDWLRQ3DWK), além de aspectos de segurança oferecidos pela própria linguagem. Foi aqui mostrado que é possível proteger informações e outros processos criptográficos através da API JCA/JCE, fornecida pela Sun Microsystems [Microsystems, 2002a]. Além disso, foi amplamente discutido o conceito de provedores de implementações criptográficas a fim deixar claro ao leitor a extensibilidade da arquitetura JCA/JCE. No que diz respeito a JAAS e JSSE, o presente artigo entrou em detalhes sobre conceitos envolvidos nessas API's e apresentou uma visão geral de sua arquitetura, definindo, assim, suas classes e interfaces primordiais. O mesmo foi feito no caso da API -DYD&HUWLILFDWLRQ3DWK. Além disso, para as API’s JCA/JCE, JAAS e JSSE foram apresentados códigos e trechos de códigos que demonstraram a real facilidade de programação utilizando essas API’s. É importante deixar claro ao leitor que as informações aqui contidas servem apenas de introdução e ilustração da tecnologia, necessitando, assim, um maior estudo em cada uma delas a fim de se obter um conhecimento substancial para a sua aplicação em sistemas comerciais. Para tal, o leitor pode consultar os manuais de referência de cada tecnologia aqui apresentada [Microsystems, 2002b], [Microsystems, 2002c], [Microsystems, 2002d], [Microsystems, 2002e] e [Mullan, 2002]. 5HIHUrQFLDV%LEOLRJUiILFDV [Microsystems, 2002a] Microsystems, S., “Sun Microsystems Homepage”. Site: www.sun.com, 2002. [Microsystems, 2002b] Microsystems, S., “Java Cryptography Architecture API Specification & Reference”. Site: http://java.sun.com/products/jdk/1.2/docs/guide/security/CryptoSpec.html, 2002. [Microsystems, 2002c] Microsystems, S., “Java Cryptography Extension {API} Specification & Reference”. Site: http://java.sun.com/products/jce/doc/guide/API_users_guide.html, 2002. [Microsystems, 2002d] Microsystems, S., “Java Authentication and Authorization Service (JAAS) Reference Guide”. Site: http://java.sun.com/j2se/1.4/docs/guide/security/jaas/JAASRefGuide.html, 2002. [Microsystems, 2002e] Microsystems, S., “Java Secure Socket Extension (JSSE) API User's Guide”. Site: http://java.sun.com/products/jsse/doc/guide/API_users_guide.html, 2002. [Microsystems, 2002f] Microsystems, S., “JAAS Authentication Tutorial”. Site: http://java.sun.com/j2se/1.4/docs/guide/security/jaas/tutorials/GeneralAcnOnly.html, 2002. [Microsystems, 2002g] Microsystems, S., “JAAS Authorization Tutorial”. Site: http://java.sun.com/j2se/1.4/docs/guide/security/jaas/tutorials/GeneralAcnAndAzn.html, 2002. [Mullan, 2002] Mullan, S., “Java Certification Path API Programmer's Guide”. Site: http://java.sun.com/j2se/1.4/docs/guide/security/certpath/CertPathProgGuide.html, 2002. [Samar, 2002] Samar, V. & Lai, C., “Making Login Services Independent of Authentication Technologies”. Site: http://java.sun.com/security/jaas/doc/pam.html, 2002. [Schneier, 1995] Schneier, B., “Applied Cryptography: Protocols, Algorithms, and Source Code in C”, , 2ª ediçã o, 1995. -RKQ :LOH\6RQV -DYD:RUOG [Srinivas, 2002] Srinivas, R. N., “Java Security Evolution and Concepts”. http://www.javaworld.com/jw-04-2000/jw-0428-security.html, 2002. . Site: [Stinson, 2002] Stinson, D., “Cryptography: Theory and Practice”. &KDSPDQ+DOO, 2ª ediçã o, 2002. [Sundsted, 2002] Sundsted, T., “Construct Secure Networked Applications with Certificates”. -DYD:RUOG. Site: http://www.javaworld.com/javaworld/jw-04-2001/jw-0413-howto.html, 2002. [Walker, 2001] Walker, C., “Security Features Overview of Merlin (J2SE Version 1.4)”. 6DQV,QVWLWXWH. Site: http://rr.sans.org/sun/merlin.php, 2001. [Zukowski, 2002] Zukowski, J., “Exploring the Security Changes of the 1.4 Release of the Java 2 Platform Standard Edition (J2SE)”. Site: http://developer.java.sun.com/developer/technicalArticles/Security/securitychange/ , 2002.