[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.

Documentos relacionados