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.