Introdução
A criptografia de senhas no backend é um passo importante no desenvolvimento de software e isso independe da tecnologia que estiver usando. Com ela nós podemos mascarar as senhas do usuário para que fiquem difíceis de adivinhar ou decodificar.
Neste tutorial vamos utilizar a biblioteca bcryptjs, uma otimização bcrypt em Javascript com zero dependências.
Como funciona o bcrypt
O bcrypt é uma biblioteca com funções utilitárias responsáveis por aplicar algoritmos de criptografia em strings, como senhas. Fornece uma ótima camada de segurança que protege de ataques como o brute-force. Ela é adaptativa ao longo do tempo e pode ir reforçando sua segurança aumentando a contagem de iterações.
Além disso, ela implementa um sistema de salts, salt em criptografia refere-se a um dado aleatório que é usado para adicionar mais segurança no hash ao ser armazenado, por exemplo, no banco de dados.
Com salts é possível se proteger contra ataques rainbow table, como também resolver problemas de duplicidade de senhas e senhas comuns, pois nesses casos o hash gerado seria igual também, mas com o salt eles serão diferentes mesmo que as strings que serão criptografadas sejam iguais.
Os salts são gerados aleatoriamente e geralmente concatenados com o hash gerado, nunca a senha original.
Criptografando uma senha em nodejs com bcryptjs
Pronto, agora que entendemos um pouco sobre o bcrypt, vamos ver como usar ele no Javascript.
Criando a estrutura
Antes de começar precisamos iniciar a estrutura e instalar a biblioteca. Na pasta em que você criará o projeto execute o seguinte comando no terminal:
1npm init -y
Esse comando irá iniciar um arquivo package.json com informações do seu projeto. Depois execute o seguinte comando para instalar a biblioteca:
1npm install bcryptjs
Pronto, agora crie um arquivo index.js
dentro da pasta.
Criptografar senhas
Agora dentro do arquivo index.js
você colocará:
1const bcrypt = require("bcryptjs"); 2const password = "tutorialdecriptografia123"; 3const salts = 10;
Primeiro estamos pegando a biblioteca bcrypt com o require, depois criamos a senha e, por último, definimos o número de salts.
Quanto maior o salt mais difícil se torna para ataques de brute-force, porém o valor é diretamente proporcional ao custo em utilização da CPU. Então, quanto maior, mais recursos serão utilizados.
Função para criar o hash e criptografar a senha
Essa é a função que gera o hash:
1async function hashingPassword(password, saltRounds) { 2 try { 3 const hashedPassword = await bcrypt.hash(password, saltRounds); 4 console.log(hashedPassword); 5 } catch (error) { 6 console.log(error); 7 } 8}
Nesse tutorial utilizaremos o método assíncrono porém também é possível usar o bcrypt sincronicamente.
Então criamos uma função assíncrona que recebe dois parâmetros: a senha que será criptografada e o valor de salts. Dentro do try usamos o método hash
do bcrypt para gerar o hash da senha, esse método recebe como parâmetros os mesmos da função.
Observação para relembrar: parâmetro é o que a função recebe, argumento é o que é passado para ela.
Por fim, damos console.log()
no resultado.
Comparando o hash com a senha
Agora criaremos uma função que será responsável por comparar o hash gerado com a senha original.
1async function comparePassword(password, hash) { 2 try { 3 const responseCompare = await bcrypt.compare(password, hash); 4 console.log(responseCompare); 5 } catch (error) { 6 console.log(error); 7 } 8}
Essa função recebe como parâmetros a senha original e o hash gerado. Dentro do try usamos o método compare
do bcrypt que faz a comparação e retorna true se o hash pertence a senha original ou false se não, o método recebe a senha e o hash como parâmetros.
Em seguida damos um console.log()
no resultado.
Resultados
Primeiro chamamos a função que irá gerar o hash passando os argumentos:
1hashingPassword(password, salts);
Aqui o resultado gerado foi o seguinte:
1// $2a$10$2dubcdUP/in4MFai840Ifebl2ciYUa0ZmnLkeLDNaFGnSSSD.c17e
Esse é o hash criptografado gerado a partir da senha “tutorialdecriptografia123” que criei lá no topo. Mas lembre-se: mesmo você usando a mesma senha que usei, o hash gerado será diferente devido ao sistema de salts. Tente executar novamente a função, você verá que o resultado será diferente, assim ocorre a cada execução.
Agora comparemos:
1comparePassword(password, "$2a$10$2dubcdUP/in4MFai840Ifebl2ciYUa0ZmnLkeLDNaFGnSSSD.c17e");
Estou chamando a função de comparação e passando como argumentos a senha e o hash gerado, o resultado que obtive com essa operação foi true
, ou seja, ele identificou que aquele hash foi gerado daquela senha, em uma aplicação de login isso significaria que o usuário digitou a senha corretamente.
Se você tentar mudar por exemplo a senha:
1comparePassword(“ihrapaz”, "$2a$10$2dubcdUP/in4MFai840Ifebl2ciYUa0ZmnLkeLDNaFGnSSSD.c17e");
A resposta será false
, assim também seria mudando um caractere do hash.
Conclusão
Vimos uma das maneiras de fazer a criptografia de strings, lembrando que tem vários outros métodos disponíveis no mercado, tanto com bcrypt quanto com outras ferramentas.
Agora você pode usar a mesma lógica para, por exemplo, salvar senhas de usuários em banco de dados com mais segurança. Basta você salvar no banco o hash invés da senha original.
Segurança é um tripé importante na criação de uma aplicação e devemos empregar o máximo de energia possível nessa etapa.