[RESOLVIDO] VRaptor - caracteres especiais via URL

Boa tarde!

Na minha aplicação, envio um email ao usuário com uma chave identificadora, utilizada pelo mesmo para validar o cadastro. Esta chave é criptografada - estou utilizando MD5.
O link que o usuário recebe é semelhante ao seguinte:

http://localhost:8080/MeuProjeto/usuario/confirmacao/2k+1xuk+dNPfhSdZn6YmQg==

onde “2k+1xuk+dNPfhSdZn6YmQg==” é a tal chave.

O problema é que, ao passar a chave acima pela URL, no meu Controller os caracteres “+” somem, e assim não iguala com o que está armazenado no banco de dados, e não valida o usuário.

Meu Controller está assim:

@Public
@Get("/usuario/confirmacao/{chaveIdentificacao}")
public void confirmar(String chaveIdentificacao) {
      [codigo]
}

Existe alguma forma de conseguir capturar todos os caracteres no Controller, ou existe algum tipo de criptografia que gere apenas letras e números?

Obrigada,

Se você está usando MD5, o mesmo deveria gerar somente caracteres hexadecimais (0 à 9 e A à F)…

Verifique o método que gera esse MD5…

Minha classe de Criptografia está assim:

package br.com.projeto.utils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import sun.misc.BASE64Encoder;

public class Criptografia {

        public static String criptografar(String valor) {
                try {
                        MessageDigest digest = MessageDigest.getInstance("MD5");
                        digest.update(valor.getBytes());
                        BASE64Encoder encoder = new BASE64Encoder();
                        return encoder.encode(digest.digest());
                } catch (NoSuchAlgorithmException ns) {
                        ns.printStackTrace();
                        return valor;
                }
        }
}

Criei isso com base em coisas que vi por aí na internet. É a primeira vez que uso algoritmos de criptografia em java, então não faço idéia se está correto. :?

O que se pode fazer é, antes de criar a URL, converter “+” para “%2B”, “=” para “%3D”, e “/” para “%2F”. São esses os caracteres especiais em Base-64.

Você está usando MD5 e Base64 encoder… O Base64 não deve ser usado dessa forma como criptografia pois ele só codifica (pode ser decodificado)…

Uma coisa legal que você pode fazer é usar o MD5 com um salt. Ou seja, você salga a String de uma forma que só você sabe como deve ser…

É uma forma de criptografia por obscuridade… Ou seja, alguém pode vir a descobrir, mas eu não me preocuparia com isso agora…

Essa aqui é uma forma de criptografia que usa o SHA-256 (parece o MD5, mas tem muito mais caracteres…)

Se você analisar, a forma que eu usei de "salgar" o meu valor é com o método shuffle e digest duas vezes… (linha 9)

[code]
public class Encrypter {

private final Logger logger = LoggerFactory.getLogger(this.getClass());

public String digest(String value) {
	if (value == null)
		throw new IllegalArgumentException("The value cannot be empty.");

	return digest(shuffle(digest(shuffle(value))));
}

private String shuffle(String value) {
	int length = value.length();

	length = getMiddle(length);

	return reverse(value.substring(0, length)).append(
			reverse(value.substring(length))).toString();
}

private StringBuilder reverse(String value) {
	return new StringBuilder(value).reverse();
}

private int getMiddle(int length) {
	if (length % 2 == 1)
		length = (length - 1) / 2;
	else
		length /= 2;
	return length;
}

private String digest(String value) {
	try {
		MessageDigest md = MessageDigest.getInstance("SHA-256");
		md.update(value.getBytes());
		return byteToHex(md.digest());
	} catch (NoSuchAlgorithmException e) {
		logger.error("Unable to digest this value.", e);
		return "";
	}
}

private String byteToHex(byte[] bytes) {
	if (bytes != null) {
		StringBuilder s = new StringBuilder();
		for (byte b : bytes) {
			int high = ((b >> 4) & 0xf) << 4;
			int low = b & 0xf;
			if (high == 0)
				s.append('0');

			s.append(Integer.toHexString(high | low));
		}
		return s.toString();
	}

	return "";
}[/code]

Analise esse código e sinta-se livre para alterá-lo à sua necessidade… Se quiser fazer com o MD5, é só trocar nessa linha MessageDigest.getInstance("SHA-256" );

Hum, legal!
Valeu pela dica!

Nesta parte do código

 private String digest(String value) {  
        try {  
            MessageDigest md = MessageDigest.getInstance("SHA-256");  
            md.update(value.getBytes());  
            return byteToHex(md.digest());  
        } catch (NoSuchAlgorithmException e) {  
            logger.error("Unable to digest this value.", e);  
            return "";  
        }  
    }

você chama o método byteToHex(md.digest()). Este método também é algo que você implementou para “reforçar”, ou faz parte da criptografia em si?
(tipo, se eu pesquisar sobre o Criptografia, sobre MessageDigest por exemplo, encontrarei este método disponível nas documentações de como implementar?).

na verdade trocar de MD5 pra SHA-256 não vai resolver o seu problema…

se vc quer que faça parte de uma url vc tem que fazer um URL encode na string… e o respectivo decode…

quem tá gerando a URL é o VRaptor ou você?

tipo, vc tem na jsp algo do tipo:

<a href="..../confirmacao/${hashMaroto}">...</a>

Se sim, vc precisa fazer o url encode.

Eu é que gero a URL.

Na verdade esta solução do Rafael resolveu meu problema, pois passou a gerar a chave criptografada apenas com letras e números.
Mas o que seria isso de “URL encode”?

o url encode converteria os caracteres especiais pra %xx que são aceitos normalmente em urls…

Certo. Bom, neste caso não vou mais precisar, mas deixarei anotado pra próximas necessidades.
Obrigada!

Só para reforçar…

Lucas, eu coloquei SHA-256 só por que eu copiei de um exemplo que eu tinha aqui… Mas a questão em si é remover o Base64 que ela estava usando junto com o MD5… O Base64 estava colocando os caracteres especiais.

Talita, eu chamo o método byteToHex por que ele converte de array de byte para String foi colocado Hex no nome por que os bytes são convertidos para os respectivos valores em Hexadecimal (0-9 e a-f)…

Eu diria que faz parte da criptografia pois precisamos dos dados em String, nesse caso…

O guava, que é uma lib obrigatória no vraptor, possui métodos para criptografia, assim não é necessário métodos caseiros.

Um simples Hashing.md5().putString("blah blah blah").hash() já faz o trabalho :slight_smile:

Garcia, eu procurei e não encontrei a classe Hashing…

Isso vem junto com o Guava que o VRaptor tem como dependência ou é um jar separado?

Olhando no Javadoc, ela foi adicionada ao guava na release 11. http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/hash/Hashing.html.

Legal, simplifica bastante. Vou deixar anotado pra dar uma olhada, assim que sobrar um tempo.