Inserido no contexto histórico de constante evolução tecnológica, há a necessidade de evoluir também o quesito relacionado à segurança da informação. Apenas o fato de possuir senhas para acesso ao sistema, não garante que este é seguro e "inabalável".
É muito comum, principalmente em serviços de Banking Online, muitas senhas, e chaves de segurança, tokens e etc., apenas para tentar garantir a segurança do usuário.
1. O Problema
Apenas salvar a senha do usuário no banco sem nenhuma criptografia é algo totalmente inseguro e até antiético. A questão da insegurança é pelo fato de que se um usuário mal intencionado consegue capturar a lista de usuários através de um SELECT qualquer ou mesmo consegue acesso ao banco, ele terá em mãos a senha de todos os usuários da sua aplicação.
Além de ele poder acessar seu sistema com qualquer usuário que desejar ele ainda pode acessar outros serviços destes usuários (email, chat's e etc.), pois geralmente eles usam a mesma senha para todos os serviços, e isso é fato já que ninguém gosta de guardar 20 senhas, 1 para cada serviço que utilize.
A questão de ser antiético é porque mesmo um funcionário autorizado a ter acesso ao banco e ver todos os dados, não pode (ou pelo menos não poderia) ler as senhas dos usuários, isso porque chegamos naquele mesmo ponto: Um usuário pode (e quase sempre o faz) utilizar a mesma senha para vários serviços.
2. A Solução
A solução básica para a situação acima descrita é aplicar algoritmos de criptografia, em específico os hash. Trabalharemos aqui com o MD5 que é um algoritmo hash de 128 bits unidirecional, ou seja, quando você codifica uma String com o MD5, não tem mais volta, você não poderá decodifica-lá para descobrir o valor real da String.
Por ser unidirecional é que o MD5 traz o "poder da segurança" em suas mãos, quer dizer que nem você (talvez um DBA com acesso total ao Banco de dados) nem qualquer outra pessoa poderão descobrir o valor original daquela String codificada em MD5.
Existem muitos sites na internet que fazem a Criptografia de Strings em MD5, porém nenhum faz o inverso. Você encontrará alguns sites que dizem supostamente fazer isso, e você verá que até acertam para algumas senhas comuns como: 123, admin, root e etc. Na verdade eles não estão decodificando o MD5 (pois até hoje isso ainda não é possível), eles possuem uma base de dados com diversas palavras que já foram codificadas e é feita apenas uma consulta a esta base de dados, nada muito complexo.
3. Aplicação Real
Precisamos pensar que se não podemos decodificar a senha que agora está em MD5, precisamos agora pensar como faremos se o usuário esquecer sua senha e também como faremos para autenticá-lo no sistema.
3.1. Autenticando Usuário no Sistema com MD5
Para autenticar o usuário você precisará codificar também a senha a qual ele deseja comparar, isso significa que você comparará MD5 com MD5, afinal não há outra forma provável de fazer isso.
Listagem 1: Realizando autenticação com MD5
public function BuscarPorEmailSenha($email, $senha) {
try {
$sql = "SELECT * FROM usuario WHERE email = :email and senha = :senha";
$p_sql = Conexao::getInstance()->prepare($sql);
$p_sql->bindValue(":email", $email);
$p_sql->bindValue(":senha", md5($senha));
$p_sql->execute();
return $this->populaUsuario($p_sql->fetch(PDO::FETCH_ASSOC));
} catch (Exception $e) {
print "Ocorreu um erro ao tentar executar esta ação, foi gerado um LOG do mesmo, tente novamente mais tarde.";
GeraLog::getInstance()->inserirLog("Erro: Código: " . $e->getCode() . " Mensagem: " . $e->getMessage());
}
}
A função acima recebe 2 parâmetros básicos para buscar um usuário no banco: Email e Senha. Sendo que "setar" o parâmetro senha no SQL, fazemos a conversão para MD5 com o método "md5()" do PHP.
3.2. "Esqueci a Senha" com MD5
Como MD5 é unidirecional e não como decodificar o codificado, é fácil perceber que não teremos como dizer ao usuário a senha que ele estava utilizando, assim sendo uma provável saída para este problema é Gerar uma nova senha e enviar ao email do usuário. Você deve ter lembrado agora que muitos serviços já fazem isso, você clica em "Esqueci minha senha" e em vez de enviarem sua senha antiga, geram uma nova, isso porque provavelmente estão trabalhando com um algoritmo hash.
Abaixo mostraremos uma função completa para gerar uma senha com toda a parametrização necessária.
Listagem 2. Gerador de Senhas
public function gerarSenha($tamanho = 8, $maiusculas = false, $numeros = true, $simbolos = false) {
// Caracteres de cada tipo
$lmin = 'abcdefghijklmnopqrstuvwxyz';
$lmai = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$num = '1234567890';
$simb = '!@#$%*-';
// Variáveis internas
$retorno = '';
$caracteres = '';
// Agrupamos todos os caracteres que poderão ser utilizados
$caracteres .= $lmin;
if ($maiusculas)
$caracteres .= $lmai;
if ($numeros)
$caracteres .= $num;
if ($simbolos)
$caracteres .= $simb;
// Calculamos o total de caracteres possíveis
$len = strlen($caracteres);
for ($n = 1; $n <= $tamanho; $n++) {
// Criamos um número aleatório de 1 até $len para pegar um dos caracteres
$rand = mt_rand(1, $len);
// Concatenamos um dos caracteres na variável $retorno
$retorno .= $caracteres[$rand - 1];
}
return $retorno;
}
O parâmetro tamanho diz respeito à quantidade de caracteres que terá a senha gerada, o parâmetro maiúsculas serve para dizer se a senha misturará maiúsculas e minúsculas, números diz se a senha terá números e símbolos diz se a senha terá símbolos.
Obviamente que a senha gerada aqui não é em MD5, pois é ela que retornaremos ao usuário, sendo assim após retornar a mesma ao usuário podemos codificá-la.
Conclusão
Não existe apenas o MD5 como algoritmo hash para criptografia de dados, o SHA-1 é outro muito conhecido e considerado sucesso do MD5. Só para ficar claro o quão é difícil a decodificação do MD5, você precisaria de 16 yottabyte de espaço para gerar todas as combinações possíveis do MD5.
Com a crescente intensificação do nível de segurança, ainda mais para aplicações críticas e sigilosas, foram criados o SHA-256 e SHA-512.