Galera, finalmente escrevo aqui no blog. Para o meu post inicial escolhi um tema bastante comentado em nossas conversas: segurança em aplicações Java.
Antes de tudo, vou falar sobre a segurança nativa a qualquer aplicação Java, provida já pela JRE. Esta segurança é feita através de um mecanismo de permissões associadas a um gerenciador de segurança (instância da classe SecurityManager), associados a uma execução do sistema (representada pela classe System).
Um SecurityManager é responsável por aplicar uma política de segurança ao sistema. Esta classe define vários métodos, com a assinatura do tipo "checkXXX(argumento, ...)", responsáveis por verificar se uma determinada operação é possível de ser executada.
Por exemplo os seguintes métodos:
- checkAccept(String host, int port) - indica se é possível aceitar conexões de Sockets a partir de um determinado host e de uma determinada porta;
- checkExit(int status) - indica se é possível terminar a execução da JVM com um determinado status;
- checkDelete(String file) - indica se é permitido remover um determinado arquivo.
Este "arquivo de polícia" pode ser definido manualmente (utililizando um editor de textos qualquer) ou através da ferramenta policytool (que acompanha qualquer distribuição do JDK).
O formato deste arquivo é o seguinte:
grant {Exemplo:
permission CLASSE_DA_PERMISSÃO "PARÂMETRO_1", "PARÂMETRO_2", "PARÂMETRO_N";
};
grant {Ao iniciar uma aplicação a JVM verifica se foi definido algum Security Manager, caso negativo, ele introduz uma implementação de acordo com o tipo da aplicação. Para applets, é introduzido um Security Manager altamente restritivo, que não permite que as aplicações acessem os recursos da máquina em que executa, por exemplo; para aplicações web o servidor web/servidor de aplicações introduz o seu próprio Security Manager, que normalmente não permite a leitura/escrita em áreas protegidas do sistema de arquivos; finalmente, para aplicações desktop, o Security Manager padrão não realiza quaisquer restrições.
permission java.io.FilePermission "C:\\users\\cathy\\foo.bat", "read";
};
Façamos agora um pequeno estudo de caso. Aplicações RMI merecem bastante atenção em relação à segurança, já que instâncias de classes serão carregadas dinâmicamente pela rede, ou seja, caso um usuário malicioso conheça o endereço do "RMI registry" e as interfaces utilizadas, é muito fácil introduzir um código malicioso neste registro, que poderá vir a ser executado por outros usuários desavisados.
No caso do RMI, a implementação atual de Java define um gerenciador de segurança (RMISecurityManager) e algumas classes de permissão que devem ser parametrizadas para a correta configuração da aplicação.
Para utilizar o gerenciador de segurança RMI, um usuário deve simplesmente fazer:
System.setSecurityManager(new RMISecurityManager());As classes de permissão definidas para ser utilizadas por este gerenciador são:
- java.io.FilePermission;
- java.net.SocketPermission;
- java.security.SecurityPermission;
- java.lang.RuntimePermission.
grant {
permission java.net.SocketPermission "*:1024-", "connect,accept";
permission java.io.FilePermission "/home/public_html/classes/-", "read";
};
grant codeBase "http://exemplo.com/classes/" {
permission java.security.AllPermission;
}
Neste exemplo acima nós podemos ver que para aplicação em questão é permitido o acesso à porta 1024 a partir de qualquer host; também é permitido apenas a leitura aos arquivos contidos no diretório "/home/public_html/classes"; finalmente, é permitido o download de classes a partir da url "http://exemplo.com/classes".
Também é possível definir as suas próprias permissões e utilizá-las em suas aplicações. Para isto, nos métodos onde serão verificadas as permissões, deve-se adicionar um código de verificação tal como:
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new ClasseDePermissao());
}
Desta forma, se não for definido nenhum gerente de segurança a aplicação irá correr normalmente, porém caso seja definido um, a sua execução será condicionada pelas permissões definidas. Para definir permissões personalizadas, um usuário tanto pode criar subclasses da classe abstrata Permission, ou pode simplesmente parametrizar a classe RuntimePermission, ex:
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("excluirRegistro"));
}
Finalmene, uma dica bem legal é utilizar um ProfilingSecurityManager, que registra todas as tentativas de acesso de uma determinada aplicação aos recursos de segurança da JVM. Desta forma nós poderemos encontrar "furos" e/ou realizar um ajuste fino da sua configuração de segurança. No link a seguir podemos ver uma discussão pormenorizada sobre a implementação/utilização de um ProfilingSecurityManager:
Link
Pessoal, é isso, concluo aqui este meu primeiro post, espero que vocês tenham gostado e que comentem, prometo complementá-lo com mais dois contendo informações sobre JAAS e Spring Security.
Nenhum comentário:
Postar um comentário