Usando criptografia no cadastro de usuários
O aplicativo desenvolvido no livro trabalha inteiramente com a senha do usuário aberta. Porém no tópico 6.8.2 damos uma dica de como configurar o Spring Security para trabalhar com a senha criptografada em MD5. O problema é que esta configuração não é suficiente para que o sistema inteiro trabalhe com a senha criptografada. Foi ai que o leitor Rafael Freitas entrou em contato e solicitou que fizessemos um post explicando como fazer esta alteração, o que faz todo o sentido.
Primeiro uma definição importante: a conhecido algoritmo Base64 na verdade é uma codificação e não criptografia, pois ele é reversível. Para ser considerada uma criptografia o algoritmo tem que ser inversível, o algoritmo MD5 tem esta capacidade.
De maneira macro, para que o sistema trabalhe com a senha do usuário criptografada algumas alterações são necessárias:
- Configuração do framework de segurança para trabalhar com a senha criptografada (já realizado no tópico 6.8.2).
- Decidir onde realizar a encriptação da senha do usuário
- Encriptar a senha do usuário
- Não exibir a senha criptografada em tela ao editar um usuário
Veremos agora o entendimento de cada alteração e depois a alteração passo a passo.
2 Decidir onde realizar a encriptação da senha do usuário
Seguindo o método utilizado no livro de sempre analisar e argumentar bem em qual camada uma alteração deve ser feita, vamos pensar sobre a alteração da senha criptografada.
A camada de acesso a dados (UsuarioDAO) deve ser imediatamente descartada, pois como já foi explicado esta camada apenas transfere dados do sistema para o banco de dados, não deve fazer qualquer alteração ou transformação.
A camada de regra de negócio (UsuarioRN) é uma forte candidata, mas como a senha do usuário será criptografada e esta criptografia é irreversível significa que a senha do usuário entrará nela aberta (ao salvar) e sairá criptografada (ao consultar). Acredito que isto pode causar alguma confusão. O ideal é que esta camada sempre trabalhe com a senha em um formato único.
Desta forma, a camada de visualização é o local correto para fazer a alteração e controlar a criptografia. Ela obrigatoriamente irá trabalhar com a senha aberta, pois é o que o usuário digita na tela, mas assim que receber esta senha deverá encriptar e enviar adiante para salvar, o que garante uma maior segurança.
3 Encriptar a senha do usuário
A encriptação da senha do usuário pode ser feita com uma classe do próprio Spring Security, conforme o exemplo a seguir:
import org.springframework.util.DigestUtils;
String senhaAberta = “teste123”;
String senhaCripto;
senhaCripto = DigestUtils.md5DigestAsHex(senhaAberta.getBytes());
System.out.println(senhaCripto);
Resultado
aa1bf4646de67fd9086cf6c79007026c
4 Não exibir a senha criptografada em tela ao editar um usuário
A partir do momento que o sistema começar a trabalhar com a senha criptografada não vai mais fazer sentido enviar esta senha para a tela, para alteração, como já é atualmente.
Não faz sentido pois pode causa confusão por dois motivos:
- A senha em MD5 é bem maior que a senha real digitada. Se o usuário digitar uma senha de 5 caracteres, em MD5 ela terá 32 caracteres. Se ao alterar um registro o usuário perceber esta senha bem maior vai estranhar e vai achar que está errado.
- Enviar a senha criptografada para a tela fará com que o campo de senha as vezes tenha uma senha aberta e outras vezes uma senha criptografada, com certeza é confuso.
Ou seja, se for o cadastro de um novo usuário a senha será preenchida normalmente, ser for uma alteração de usuário o campo senha deverá ser mantido em branco e o usuário somente preencherá este campo de quiser alterar a senha, senão deixa em branco.
Com isso definimos um comportamento do sistema: o campo de senha só será preenchido com senha aberta.
Porém se a senha for deixada em branco (significando que o usuário quer manter a senha antiga), como vamos salvar o registro do usuário se esta senha está em branco?
O segredo aqui é guardar a senha criptografada do usuário em outro local, quando a tela for aberta para edição (veremos como fazer no passo a passo).
Para manter o campo da senha em branco e considerar que ele só será preenchido quando o usuário quiser alterar existem duas opções:
1. Colocar um aviso junto ao campo dizendo: Preencher somente se quiser alterar.
2. Usar o componente do Primefaces WaterMark, que mostrará a mesma mensagem anterior, só que dentro do campo. http://www.primefaces.org/showcase/ui/watermark.jsf
Fazendo a alteração passo a passo
<h:inputHidden value=”#{usuarioBean.senhaCriptografada}”/>
public String editar() {
this.senhaCriptografada = this.usuario.getSenha();
return "/publico/usuario";
}
public String salvar() { FacesContext context = FacesContext.getCurrentInstance(); String senha = this.usuario.getSenha(); if (senha != null && senha.trim().length() > 0 && !senha.equals(this.confirmarSenha)) { FacesMessage facesMessage = new FacesMessage("A senha não foi confirmada corretamente"); context.addMessage(null, facesMessage); return null; } if (senha != null && senha.trim().length() == 0) { this.usuario.setSenha(this.senhaCriptografada); } else { String senhaCripto = DigestUtils.md5DigestAsHex(senha.getBytes()); this.usuario.setSenha(senhaCripto); } UsuarioRN usuarioRN = new UsuarioRN(); usuarioRN.salvar(this.usuario); [...] }
Tags: javaparaweb, javaserver faces, jsf, md5, novatec, primefaces, xhtml
December 3rd, 2010 at 23:33
Só queria registrar que o md5 é reversível sim. com uma simples busca no google pela reversão de uma string embaralhada pelo md5 mostra um site que faz isso…
Mas belo post!
December 7th, 2010 at 17:13
Olá Rodrigo. O que encontrei foram sites que procuram o hash md5 na internet ou em um banco de dados pela string original que o gerou. Por exemplo, o hash utilizado no post é uma senha muito comum “teste123”, nem é preciso reverse pra encontrar outros sites que utilizaram o mesmo exemplo.
Outro exemplo, o hash da palavra “xpto999” nenhum site conseguiu reverter, mas o hash da palavra “dog” todos conseguiram. Simplesmente porque são palavras comuns e que já estavam no ‘dicionário’.
Mas você tem razão, apesar de não ser uma reversão perfeita, ele consegue resolver alguns casos, o que diminui a segurança do MD5. Assim, de qualquer forma, as antigas regras de segurança de senha garantem uma segurança maior.
Mas é isso, nenhuma segurança é perfeita, elas só conseguem dar mais trabalho para quem quer quebrar. Talvez eu não encontrei este site exato que você comentou, tente validar isso que eu falei, se você tiver o site que faça a reversão exata mande mais um comentário.
agradeço a sua contribuição
abraços
Décio
January 27th, 2011 at 18:44
Boa tarde, amigos.
Primeiramente quero parabenizá-los pela bela obra. Só que estou encontrando alguma dificuldade no código do capítulo 3 da locadora. Digitei o código do livro, fiquei três dias quebrando a cabeça, rodei o script do banco, copiei o código fonte para a IDE e mesmo assim não cadastra. Não sei o que está acontecendo e pediria que fosse feita uma revisão.
Abraços!
February 1st, 2011 at 01:21
Olá Carlos, desculpe a demora, acabei ficando alguns dias sem verificar os comentários do blog. Acabei de instalar um forum para os leitores tirarem dúvidas sobre os capítulos, peço que direcione as suas dúvidas no forum para lhe respondermos e para que suas dúvidas possam ajudar outras pessoas também.
http://www.javaparaweb.com.br/forum
Mais uma vez desculpe a demora, de qualquer forma, precisaremos de mais informações sobre o erro, no forum publique o descritivo das exceções que ocorreram. Até agora os leitores não tem apresentado dificuldade neste capítulo, então acredito que não seja erro no livro.
abraços
Décio Luckow
February 9th, 2012 at 20:09
VALEU, funcionou, só uma ressalva no banco de dados mudem o tamanho do campo de 10 para 32 ….Abraçosssssss
July 7th, 2012 at 17:39
Parabéns pelo livro!!
Uma pergunta : Há como CRIPTOGRAFAR a senha do banco usada no XML ??
root
July 19th, 2012 at 00:43
Olá, naturalmente não tem como criptografar, mas tem como você guardar a senha criptografada em outro lugar e setar no hibernate programaticamente, veja este post: http://www.guj.com.br/java/33071-criptografar-a-senha-de-acesso-no-arquivo-de-configuracao-do-hibernate