Argon2 é uma função de derivação de chave indicada para armazenar senhas. Ela foi projetada para ser cara em memória e processamento, dificultando ataques com GPUs e hardware especializado. Em aplicações Node.js, use uma biblioteca mantida, parâmetros medidos no ambiente real e Argon2id como variante padrão quando disponível.
Senhas não devem ser criptografadas de forma reversível nem armazenadas com hash rápido como SHA-256. O servidor precisa guardar um hash lento com salt aleatório e parâmetros incorporados.
Instalação
npm install argon2Gerando o hash
import argon2 from 'argon2';
const passwordHash = await argon2.hash(password, {
type: argon2.argon2id,
memoryCost: 65536,
timeCost: 3,
parallelism: 1,
});A string resultante inclui algoritmo, versão, parâmetros, salt e hash. Armazene-a inteira.
Verificando
const valid = await argon2.verify(user.passwordHash, password);
if (!valid) {
throw new AuthenticationError('Credenciais inválidas');
}Use a mesma resposta para usuário inexistente e senha incorreta, reduzindo enumeração de contas.
Argon2id
Argon2id combina características de Argon2i e Argon2d. Ele busca resistência a ataques de canal lateral e ataques por hardware paralelo. Não troque a variante sem revisar o modelo de ameaça.
Memory cost
memoryCost representa memória por cálculo. Valores maiores dificultam ataques, mas também reduzem concorrência do servidor. Quatro logins simultâneos com 64 MiB podem consumir cerca de 256 MiB apenas no hashing.
Time cost
timeCost controla iterações. O objetivo é tornar o hash suficientemente caro sem causar timeout ou negação de serviço. Meça p95 em hardware de produção e sob concorrência.
Parallelism
Mais lanes podem usar múltiplos núcleos, mas o benefício depende da implementação e do ambiente. Em containers com CPU limitada, valor alto pode piorar latência e throttling.
Benchmark de parâmetros
const start = performance.now();
await argon2.hash('senha-de-teste', options);
console.log(performance.now() - start);Execute várias rodadas, descarte aquecimento e teste concorrência. Um alvo comum é algumas centenas de milissegundos, mas o valor correto depende do risco e da capacidade.
Salt
A biblioteca gera salt aleatório automaticamente. Não use email, ID ou salt global. Salt não é secreto e impede que hashes iguais revelem senhas iguais.
Pepper
Um pepper é um segredo adicional mantido fora do banco:
const input = `${password}${process.env.PASSWORD_PEPPER}`;
const hash = await argon2.hash(input, options);O pepper pode reduzir impacto de vazamento apenas do banco, mas exige rotação e disponibilidade. Armazene em secret manager, não no código.
Rotação de pepper
Mantenha um identificador de versão. Ao validar com pepper antigo, gere novo hash com a versão atual. Uma troca imediata exige reset de senha de todos os usuários, pois o servidor não conhece as senhas.
Rehash automático
if (argon2.needsRehash(user.passwordHash, currentOptions)) {
const nextHash = await argon2.hash(password, currentOptions);
await users.updatePasswordHash(user.id, nextHash);
}Atualize depois de login bem-sucedido. Use operação segura para não perder o hash em falha de banco.
Migração de bcrypt
Identifique o formato do hash. Valide com bcrypt e, após sucesso, rehash com Argon2id. Não tente converter um hash sem a senha original.
Limite de tamanho da senha
Defina um limite alto, como centenas ou alguns milhares de caracteres, para evitar payloads gigantes. Não trunque silenciosamente. Permita passphrases e gerenciadores de senha.
Normalização
Normalizar Unicode pode alterar senhas existentes. Defina a política desde o início e não faça mudanças invisíveis. Em geral, trate a senha exatamente como fornecida após validar tipo e tamanho.
Login e rate limiting
Hashing é caro por design e pode ser usado em ataque de CPU. Aplique rate limiting por IP e conta, limites de concorrência e filas curtas. Não reduza parâmetros apenas para suportar abuso.
Usuário inexistente
Para reduzir diferença de tempo, execute verificação contra um hash fictício válido quando o usuário não existe:
const hash = user?.passwordHash || DUMMY_HASH;
const valid = await argon2.verify(hash, password);
if (!user || !valid) {
throw new AuthenticationError('Credenciais inválidas');
}Worker Threads
A biblioteca pode usar implementação nativa e threads internas. Meça o event loop e a CPU. Um pool externo de Worker Threads só deve ser adicionado se profiling demonstrar benefício.
Reset de senha
Tokens de reset devem ser aleatórios, de uso único, com TTL curto e hash no banco. Após redefinição, revogue sessões e refresh tokens conforme a política.
Política de senha
Prefira comprimento, bloqueio de senhas comprometidas e MFA em vez de regras complexas de caracteres. Não limite colagem; usuários precisam usar gerenciadores.
Logs
Nunca registre senha, hash, pepper ou token de reset. Redija bodies e erros. Métricas devem conter apenas resultado agregado e duração.
Erros comuns
- usar SHA-256 ou MD5;
- gerar salt manual previsível;
- armazenar pepper no banco;
- parâmetros sem benchmark;
- não limitar tentativas;
- truncar senhas;
- registrar hash ou senha;
- não atualizar parâmetros antigos;
- comparar strings manualmente;
- usar criptografia reversível.
Testes
Teste hash e verify, senha incorreta, hash inválido, needsRehash, pepper antigo, migração, concorrência, limite de tamanho e falha do secret manager.
Fluxo recomendado
- use Argon2id;
- faça benchmark;
- configure memória e tempo;
- deixe a biblioteca gerar salt;
- considere pepper protegido;
- use rate limiting;
- rehash após login;
- revogue sessões após reset;
- redija logs;
- revise parâmetros anualmente.
Combine Argon2 com Secret Management, Rate Limiting, Worker Threads e Refresh Tokens.
Consulte a documentação do node-argon2 e o guia de armazenamento de senhas da OWASP.



