-
Notifications
You must be signed in to change notification settings - Fork 370
031. Hash das passwords
O PR #162 implementa o hash
das senhas, e utiliza um método de criptografia bem popular chamado bcrypt... é quase que um padrão na comunidade de Node.js. Mas escolher o módulo que implementa esse método foi interessante, porque o padrão de todos os tutoriais é usar o bcrypt
, porém há uma alternativa mais popular chamada bcryptjs
que faz a exata mesma implementação, mas utilizando apenas JavaScript, ao invés de depender da compilação de binários como faz o bcrypt
. O tradeoff em se usar a alternativa em JavaScript é uma perda de 30% de performance na hora de calcular os hashes (o que pessoalmente achei pouco até), mas ganhar compatibilidade total em qualquer ambiente Node.js que você for rodar o código, o que pode não acontecer com o bcrypt
. Como vamos rodar na Vercel onde não queremos nos importar com o ambiente, achei prudente aceitar o tradeoff e mirar na compatibilidade.
O método de criptografia bcrypt usa uma estratégia muito legal, que é consumir o potencial de processamento para criar o hash e o quão difícil é fazer isso é definido pela propriedade round
do salt
(que por conveniência acaba sendo concatenado na própria string da hash). E quanto maior o round
e mais difícil computar, também fica mais difícil para alguém quebrar um hash caso aconteça o vazamento desse dado. O problema é que você pode aumentar tanto esse valor que ficará inviável para os dois lados o hacker e o seu sistema, que irá suar a cada criação ou verificação de senha.
Nos meus testes locais e sem utilizar nenhuma estratégia de hash, a bateria de testes automatizados rodavam em cerca de 2 segundos. Agora olha a tabela abaixo que interessante que o jogo de "aumentar a dificuldade dos rounds" começa a ficar. Na esquerda da tabela temos os rounds
e na direita o tempo que levou para concluir a bateria de testes (use como referência os 2 segundos anteriores sem hash algum).
rounds | tempo |
---|---|
1 | 2s |
5 | 2s |
10 | 4s |
11 | 7s |
12 | 12s |
13 | 22s |
14 | 44s |
15 | 93s |
Esse não é um teste científico, porque minha máquina não estava num estado "em branco", mas mesmo assim, o impacto na performance é impressionante e nos testes com os últimos rounds, a minha máquina ligou a ventoinha e me chamou pra conversar.
Cavucando na internet, não há um consenso exato de quantos rounds utilizar. Há cálculos que levam em consideração a evolução dos processadores, e também um certo chute da galera de usar entre 10
rounds em post mais antigos e 12
rounds em posts mais novos.
Minha sugestão é: para o ambiente de produção, vamos usar 14
rounds e ver como o sistema se comporta (até porque, isso pode penalizar a experiência do usuário). E eu destaquei o ambiente de produção, porque eu comecei a odiar rodar os testes automatizados localmente, mesmo isolando só o api/v1/user
por exemplo... e isso não é um bom sinal. Sair de "2 segundos" para "44 segundos" não foi uma sensação boa. Aí tive a ideia de separar os ambientes, onde em produção deixar os 14
mas em ambiente local deixar 1
. O bom é que o tamanho do hash gerado é sempre o mesmo, independente do número de rounds.
São preocupações naturais, mas que vou escrever aqui para deixarmos a anteninha em pé:
- Um bug no módulo
password.js
ou mau configuração no ambiente de produção que comece a fazer os hashes serem gerados com apenas 1 round. Pelo menos no código eu primeiro seto a variável em14
e verificando o ambiente eu faço a retribuição do valor para1
. - Mau configuração no banco de dados que não está dentro de uma VPC e precisa estar exposto de forma pública para que a Vercel consiga acessar.
- Brechas no sistema de autenticação e autorização.