bcrypt vs Argon2 vs scrypt: hash de senhas em 2026
Resposta curta: para qualquer projeto novo em 2026, use Argon2id com m=19456, t=2, p=1. Esse é o baseline do OWASP Password Storage Cheat Sheet, e é o algoritmo de hash de senhas com a maior resistência a GPU e a canais laterais que você consegue colocar em produção hoje.
Se Argon2 não estiver disponível na sua stack (raro, mas acontece em alguns runtimes embarcados ou mais antigos), escolha scrypt com N=2^17, r=8, p=1. Use bcrypt com cost=12 apenas quando você estiver preso a um sistema legado que já fala bcrypt e não puder adicionar uma nova dependência. Fique com PBKDF2-HMAC-SHA-256 com 600.000 iterações quando a conformidade FIPS-140 for obrigatória.
| Algoritmo | Parâmetros OWASP 2026 | Quando escolher |
|---|---|---|
| Argon2id | m=19456 KiB, t=2, p=1 | Padrão para projetos novos |
| scrypt | N=2^17, r=8, p=1 | Argon2 indisponível |
| bcrypt | cost=12 (mín. 10) | Apenas sistemas legados |
| PBKDF2 | HMAC-SHA-256, 600k iterações | FIPS-140 obrigatório |
O resto do artigo explica por que esses números, como ajustá-los para o seu hardware e como migrar sem forçar um reset de senha. Precisa gerar senhas fortes para benchmarking? Use o Gerador de Senhas Aleatórias. Para o panorama mais amplo, veja o guia de Segurança Web Essencial.
Por que hash de senhas é diferente de hash genérico
Funções de hash, vistas de fora, parecem todas iguais: entram dados, sai um digest de tamanho fixo, e você não consegue reverter. Mas os objetivos de design para “fazer hash deste ISO de 4 GB” e “fazer hash desta senha de 12 caracteres” são exatamente opostos. Um deve ser tão rápido quanto o silício permitir. O outro deve ser tão lento quanto o orçamento de latência do seu login tolerar.
Confundir esses dois cenários é como vazamentos de banco viram tomadas de conta.
Por que MD5 e SHA-256 não bastam para senhas
Hashes de uso geral como MD5, SHA-1 e SHA-256 foram projetados para throughput. Eles processam gigabytes por segundo em CPUs comuns e dezenas de gigabytes por segundo em GPUs. Isso os torna excelentes para checksums de arquivos e endereçamento por conteúdo, e desastrosos para senhas.
Benchmarks do Hashcat em uma única RTX 4090 mostram cerca de 164 GH/s para MD5 e 22 GH/s para SHA-256 em 2024. Uma senha de oito caracteres com letras minúsculas e dígitos (36^8 ≈ 2,8 × 10^12 candidatos) cai em uma única GPU em menos de um minuto contra MD5 e em menos de dois minutos contra SHA-256. Um banco de dados vazado armazenando sha256(password) é praticamente texto puro.
E o salt não te salva. O salt impede que tabelas rainbow pré-computadas funcionem, mas não faz nada para frear um ataque por conta: o atacante simplesmente faz hash de cada candidato concatenado com o salt vazado.
Para checksums fora do contexto de segurança, MD5 e SHA-256 continuam úteis, e é para isso que existem ferramentas como o Gerador de Hash MD5. Para uma comparação aprofundada de quando cada algoritmo é apropriado, leia MD5 vs SHA-256. Mas para senhas, você precisa de um hash deliberadamente lento.
As três propriedades de um hash de senha moderno
Um hash de senha digno de produção em 2026 tem três propriedades:
- Lento por design, com fator de trabalho ajustável. O login deve levar 100–500 ms, rápido o suficiente para o usuário não perceber, lento o suficiente para um atacante offline queimar dias por milhão de tentativas. O fator de trabalho precisa ser um parâmetro para você poder aumentá-lo conforme o hardware evolui.
- Salt por registro. Um salt aleatório único por senha derrota tabelas rainbow e força o atacante a atacar cada conta individualmente. Algoritmos modernos geram e embutem o salt na string de saída para você.
- Memory-hard. GPUs e ASICs são rápidos em computação, mas caros em memória de alta largura de banda. Um algoritmo que exige dezenas de MiB por hash força o atacante a provisionar RAM proporcional ao seu paralelismo, matando a relação custo-benefício de farms de GPU.
bcrypt acerta (1) e (2), mas não (3). scrypt foi o primeiro algoritmo a atingir as três. Argon2 refinou o design e venceu a Password Hashing Competition. A próxima seção destrincha cada um.
Os três algoritmos: arquitetura e tradeoffs
bcrypt: baseado em Blowfish, time-hard
bcrypt foi projetado em 1999 por Niels Provos e David Mazières para o OpenBSD. Ele é construído em cima da cifra Blowfish, com uma fase cara de key-setup (“EksBlowfish”) repetida 2^cost vezes. O único parâmetro ajustável é o fator de custo (também chamado de “log rounds”): cada incremento dobra o trabalho. Um hash com cost=10 faz 1.024 key schedules; cost=14 faz 16.384.
Um hash bcrypt tem esta cara:
$2b$12$R9h/cIPz0gi.URNNX3kh2OPST9/PgBkqquzi.Ss7KIUgO2t0jWMUW
│ │ │ │
│ │ │ └─ hash base64 de 31 caracteres
│ │ └─ salt base64 de 22 caracteres
│ └─ fator de custo (12)
└─ identificador do algoritmo ($2b$ = bcrypt v2)
O formato é autodescritivo: o verify() lê o custo e o salt da string armazenada, sem precisar de colunas separadas.
As desvantagens são reais. A pegada de memória do bcrypt é de cerca de 4 KiB, pequena o suficiente para uma GPU topo de linha rodar milhares de núcleos bcrypt em paralelo. E o bcrypt trunca silenciosamente a entrada em 72 bytes. Uma frase-passe de 100 caracteres tem a mesma segurança que seus primeiros 72 bytes. O custo máximo é 31, mas qualquer coisa acima de ~16 começa a doer na latência de login em hardware comum.
scrypt: o pioneiro memory-hard
scrypt foi publicado em 2009 por Colin Percival para o serviço de backup Tarsnap e padronizado como RFC 7914 em 2016. Ele introduziu a ideia de memory-hardness: o algoritmo preenche um buffer grande com dados pseudoaleatórios, depois lê de posições aleatórias, forçando qualquer implementação a alocar a memória de fato.
scrypt tem três parâmetros:
N: custo de CPU/memória (precisa ser potência de 2)r: tamanho do bloco em bytes (multiplicador de memória e rodadas de mistura)p: paralelismo (computações independentes, usado principalmente para escalar tempo de CPU sem escalar memória)
O uso de memória é aproximadamente 128 × N × r bytes. Com os valores recomendados pela OWASP (N=2^17, r=8), isso dá 128 × 131072 × 8 = 134.217.728 bytes, ou seja, 128 MiB por hash.
scrypt também é uma função de derivação de chave, não apenas um hash de senha. Ele é usado em carteiras de criptomoeda, criptografia de disco completo e na proof-of-work original do Litecoin. Esse papel duplo é conveniente quando você precisa de armazenamento de senhas e derivação de chave na mesma biblioteca.
Argon2 (id/i/d): vencedor da Password Hashing Competition
A Password Hashing Competition rodou de 2013 a 2015, avaliando 24 algoritmos candidatos quanto a memory-hardness, resistência a canais laterais e simplicidade de implementação. Argon2 venceu. Foi padronizado como RFC 9106 em 2021.
Argon2 tem três variantes. As diferenças se resumem a como a memória é endereçada durante a mistura:
- Argon2d usa endereços de memória dependentes dos dados. Isso maximiza a resistência a ataques de GPU e ASIC, mas vaza informação por canais laterais de cache-timing. Adequado para proof-of-work de criptomoeda, não para autenticação.
- Argon2i usa endereços independentes dos dados. Seguro contra canais laterais, mas levemente mais fraco contra ataques tradeoff em GPU.
- Argon2id é um híbrido: a primeira metade da primeira passada usa indexação Argon2i (segura contra canais laterais), e o resto usa indexação Argon2d (resistente a GPU). A RFC 9106 recomenda explicitamente Argon2id para hash de senhas, e a OWASP também.
Argon2 tem três parâmetros:
m: memória em KiBt: custo de tempo (número de passadas sobre o buffer de memória)p: paralelismo (número de pistas processadas concorrentemente)
Um hash Argon2id usa o formato de string PHC e tem esta cara:
$argon2id$v=19$m=19456,t=2,p=1$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG
Como no bcrypt, todos os parâmetros estão embutidos na string, então o verify() não precisa de uma tabela de parâmetros.
Parâmetros recomendados pela OWASP em 2026
O OWASP Password Storage Cheat Sheet é a referência canônica. Os números abaixo batem com a orientação atual. Eles são conservadores, dimensionados para um servidor web típico com orçamento de latência de login de 100–500 ms, e mesmo assim você deve fazer benchmark no seu próprio hardware antes de subir para produção.
Parâmetros do Argon2id: primeira escolha
Recomendação baseline da OWASP: m=19456 (19 MiB), t=2, p=1.
Se o seu servidor tiver mais folga de RAM, você pode deslocar o trabalho entre memória e tempo. A RFC 9106 publica perfis equivalentes; a OWASP recomenda qualquer um destes:
| memoryCost (m) | timeCost (t) | parallelism (p) | RAM por hash |
|---|---|---|---|
| 47104 | 1 | 1 | 46 MiB |
| 19456 | 2 | 1 | 19 MiB (baseline) |
| 12288 | 3 | 1 | 12 MiB |
| 9216 | 4 | 1 | 9 MiB |
| 7168 | 5 | 1 | 7 MiB |
Regra de bolso para tuning: escolha m primeiro com base no orçamento de RAM no pico de logins concorrentes. Se você espera 100 logins simultâneos e tem 4 GiB de sobra, isso dá 40 MiB por hash. Depois aumente t até um único verify levar 100–500 ms na CPU de produção. Deixe p=1 a menos que você tenha uma razão específica para mexer (a maioria dos frameworks web já dá uma thread própria por requisição).
Parâmetros do scrypt: quando Argon2 não está disponível
Recomendação da OWASP: N=2^17 (131072), r=8, p=1, que usa 128 MiB por hash.
Se 128 MiB por login concorrente for demais para o seu servidor, a OWASP permite perfis mais fracos:
| N | r | p | RAM por hash |
|---|---|---|---|
| 2^17 | 8 | 1 | 128 MiB (preferido) |
| 2^16 | 8 | 1 | 64 MiB |
| 2^15 | 8 | 1 | 32 MiB |
N precisa ser potência de dois. Aumentar r aumenta memória e CPU proporcionalmente; aumentar p aumenta o trabalho de CPU sem aumentar a memória por instância. Para hash de senhas, deixe r e p nos defaults e ajuste só N.
bcrypt: fator de custo 10+ apenas para legado
A OWASP não recomenda mais bcrypt para projetos novos, mas ele continua em todo lugar: Devise, Spring Security, ASP.NET Identity e inúmeros sistemas de auth caseiros usam ele por padrão.
Se você está preso ao bcrypt, as regras são:
- Fator de custo mínimo do bcrypt: 10. Abaixo disso é rápido o suficiente para uma única GPU terminar uma base vazada em dias.
- Recomendado: 12 a 14, dependendo do hardware. Em um servidor x86 moderno,
cost=12leva uns 250 ms por hash;cost=13leva 500 ms. - Mire em 100–300 ms por verify no seu hardware de produção. Faça benchmark, não chute.
- Lembre-se do limite de 72 bytes na entrada. Se os usuários puderem escolher frases-passe, faça pré-hash com SHA-256 (veja o FAQ).
A resistência do bcrypt a GPU é limitada pela sua pegada de 4 KiB de memória. Nenhum fator de custo do bcrypt vai igualar a memory-hardness do Argon2id, então escolha Argon2id quando puder.
Uma referência prática: em um servidor EPYC de 2024, bcrypt(cost=12) roda em cerca de 250 ms; em um laptop topo de linha, mais perto de 350 ms. Se os seus números ficarem fora da faixa 100–500 ms por uma ordem de grandeza, confira se a sua biblioteca está realmente fazendo bcrypt nativo ou caindo num polyfill JavaScript lento (alguns bundlers removem dependências nativas em builds serverless).
PBKDF2: o caminho da conformidade FIPS-140
PBKDF2 (RFC 8018) é o algoritmo de último recurso quando o assunto é orientação de segurança. Ele é mais antigo que o bcrypt, não é memory-hard, e cai para ataques de GPU mais rápido do que qualquer um dos três acima. Mas é a única primitiva de hash de senhas com validação FIPS-140, o que importa para o governo federal, HIPAA na saúde e certas implantações financeiras.
Quando precisar de PBKDF2, use:
- HMAC-SHA-256 como PRF (não use SHA-1; não use SHA-256 puro sem HMAC)
- 600.000 iterações no mínimo (baseline OWASP 2026)
- Pelo menos 16 bytes de salt aleatório por senha
Se FIPS não se aplica a você, prefira Argon2id. O design de saída fixa e memória fixa do PBKDF2 significa que cada dólar de silício de GPU que o atacante compra se traduz diretamente em mais tentativas de senha por segundo.
A SP 800-63B do NIST chama o PBKDF2-HMAC de “aprovado” para hash de senhas, mas para por aí: não chega a recomendá-lo em vez das alternativas memory-hard. Leia isso assim: o NIST permite PBKDF2 porque aposentá-lo invalidaria toda implantação legada do governo, não porque ele seja a melhor escolha para um projeto novo.
Estrutura de decisão: qual algoritmo escolher?
Tabela comparativa
| Dimensão | bcrypt | scrypt | Argon2id | PBKDF2 |
|---|---|---|---|---|
| Memory-hard | Não | Sim | Sim | Não |
| Resistência a GPU | Média | Alta | Muito alta | Baixa |
| Resistência a canais laterais | Média | Média | Alta (id) | Média |
| Complexidade de parâmetros | 1 (cost) | 3 (N, r, p) | 3 (m, t, p) | 1 (iterations) |
| Maturidade da biblioteca | Excelente | Boa | Boa | Excelente |
| Limite de tamanho da entrada | 72 bytes | Nenhum | Nenhum | Nenhum |
| Padronização | de facto | RFC 7914 | RFC 9106 | RFC 8018 |
| Status OWASP 2026 | Apenas legado | Alternativa | Primeira escolha | Apenas FIPS |
Use Argon2id por padrão
Para um projeto novo (app web típico, stack moderna em Node/Python/Go/Rust/JVM, sem restrição FIPS), use Argon2id com m=19456, t=2, p=1. Você ganha a maior resistência a GPU e a canais laterais disponível, um formato com parâmetros embutidos que sobrevive a upgrades de biblioteca, e nenhuma surpresa de tamanho de entrada. O ecossistema de bibliotecas é maduro: argon2 no npm, argon2-cffi no PyPI, golang.org/x/crypto/argon2, crate argon2 no crates.io, todos mantidos e com benchmarks.
Quando escolher scrypt ou bcrypt
Escolha scrypt quando Argon2 não estiver disponível no seu runtime (genuinamente raro em 2026, mas até Cloudflare Workers e Deno têm agora), ou quando você já tem um sistema baseado em scrypt em produção e o custo de migração supera o ganho de segurança. scrypt continua sendo um algoritmo sólido; ele só não tem o polimento do Argon2id contra canais laterais.
Escolha bcrypt quando você está mantendo um sistema legado, tem um requisito rígido de minimização de dependências (sem código nativo, sem pacotes extras), e o limite de 72 bytes na entrada é aceitável para a sua base de usuários. bcrypt foi implantado em escala de internet por duas décadas; seus modos de falha são bem entendidos.
Escolha PBKDF2 quando o regulador mandar. Esse é o único motivo. Se o seu auditor aceitar Argon2id (o que cada vez mais aceitam para cargas que não são FIPS), use Argon2id.
Erros comuns a evitar
A maioria dos vazamentos de armazenamento de senhas da última década rastreia até um conjunto pequeno de erros recorrentes de engenharia. Nenhum deles é exótico; todos são pegos revisando seu código de auth com a lista abaixo na frente.
- Fazer hash de senhas com SHA-256 ou MD5 puros. Esse é o maior fracasso isolado em armazenamento de senhas. Veja MD5 vs SHA-256 para entender por que esses são errados para senhas.
- Reutilizar um único salt global em todos os usuários. O salt tem que ser único por registro. Argon2 e bcrypt geram um para você; não sobrescreva isso.
- Definir o tempo de hash abaixo de 50 ms. Você trocou segurança por uma melhoria de velocidade que nenhum usuário consegue perceber. Mire em 100–500 ms.
- Definir o tempo de hash acima de 1 segundo. Você criou um vetor de negação de serviço contra o seu próprio endpoint de login. Limite em ~500 ms.
- Fazer hash da senha no cliente e mandar o digest para o servidor. O hash agora é a senha. Quem rouba o banco autentica sem nunca ter de invertê-lo. Sempre faça hash no servidor.
- Armazenar os parâmetros do algoritmo numa coluna separada. O formato de string PHC já os embute no hash. Use isso.
- Logar senhas ou hashes durante tratamento de erro. Os dois pertencem ao usuário, não ao seu agregador de logs. Limpe-os na camada de parsing da requisição antes de chegarem em qualquer logger.
- Tratar exceções do
verify()como falha de autenticação. Uma biblioteca que lança erro num hash armazenado malformado deveria fazer aflorar o erro, não silenciosamente cair em “senha errada”. Distinga entre “senha errada” (retorne 401) e “hash armazenado corrompido” (retorne 500 e acione o on-call).
Implementação no mundo real
Argon2id em Node.js
O pacote argon2 (bindings nativos para a implementação de referência) é a escolha canônica em Node:
import argon2 from 'argon2';
// Hash no signup ou na troca de senha
const hash = await argon2.hash(password, {
type: argon2.argon2id,
memoryCost: 19456, // 19 MiB
timeCost: 2,
parallelism: 1,
});
// → '$argon2id$v=19$m=19456,t=2,p=1$<salt>$<hash>'
// Verificação no login
const ok = await argon2.verify(hash, candidate);
if (!ok) throw new Error('Invalid credentials');
// Detecta parâmetros desatualizados e refaz o hash em login bem-sucedido
if (argon2.needsRehash(hash, { type: argon2.argon2id, memoryCost: 19456, timeCost: 2, parallelism: 1 })) {
const upgraded = await argon2.hash(candidate, {
type: argon2.argon2id, memoryCost: 19456, timeCost: 2, parallelism: 1,
});
await db.users.update({ id: user.id }, { password_hash: upgraded });
}
O passo do needsRehash é o segredo da migração de longo prazo: cada login bem-sucedido vira oportunidade de subir o hash armazenado para os parâmetros atuais, sem incomodar o usuário.
O mesmo padrão em Python com argon2-cffi:
from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError
ph = PasswordHasher(memory_cost=19456, time_cost=2, parallelism=1)
# Hash
stored = ph.hash(password)
# Verificação
try:
ph.verify(stored, candidate)
except VerifyMismatchError:
raise ValueError('Invalid credentials')
# Re-hash quando os parâmetros sobem
if ph.check_needs_rehash(stored):
stored = ph.hash(candidate)
Em Go com golang.org/x/crypto/argon2:
import (
"crypto/rand"
"golang.org/x/crypto/argon2"
)
func hashPassword(password string) ([]byte, []byte) {
salt := make([]byte, 16)
rand.Read(salt)
hash := argon2.IDKey([]byte(password), salt, 2, 19456, 1, 32)
return hash, salt
}
A standard library do Go não traz um encoder em formato PHC; se você usar a primitiva argon2.IDKey direto, é responsável por codificar os parâmetros e o salt junto com o hash. A maioria dos projetos Go usa um wrapper como github.com/alexedwards/argon2id para isso.
Em Rust, com a crate argon2, é igualmente idiomático:
use argon2::{Argon2, PasswordHasher, PasswordVerifier, password_hash::{SaltString, rand_core::OsRng}};
let salt = SaltString::generate(&mut OsRng);
let argon2 = Argon2::default(); // Argon2id, m=19456, t=2, p=1 por padrão
let hash = argon2.hash_password(password.as_bytes(), &salt)?.to_string();
// Na verificação
let parsed = argon2::password_hash::PasswordHash::new(&hash)?;
argon2.verify_password(candidate.as_bytes(), &parsed)?;
Nos três runtimes, a string produzida é intercambiável: um hash criado em Node verifica certinho em Python ou Rust. Essa compatibilidade entre runtimes faz do Argon2 uma aposta mais segura para arquiteturas poliglotas do que wrappers específicos de algoritmo.
Padrão de migração de bcrypt para Argon2id
Você quase nunca tem o luxo de zerar a tabela de usuários e começar de novo. O padrão certo de migração é o mesmo usado na seção de migração MD5-para-bcrypt do FAQ do nosso Gerador de Hash MD5: um upgrade suave, dirigido pelo login.
Adicione uma coluna registrando o algoritmo:
ALTER TABLE users ADD COLUMN password_algo VARCHAR(16) NOT NULL DEFAULT 'bcrypt';
No login, despache para o verificador correto:
async function verifyAndMaybeRehash(user, candidate) {
let ok;
if (user.password_algo === 'argon2id') {
ok = await argon2.verify(user.password_hash, candidate);
} else if (user.password_algo === 'bcrypt') {
ok = await bcrypt.compare(candidate, user.password_hash);
if (ok) {
// Verify legado bem-sucedido → refaz o hash com Argon2id
const newHash = await argon2.hash(candidate, {
type: argon2.argon2id, memoryCost: 19456, timeCost: 2, parallelism: 1,
});
await db.users.update({ id: user.id }, {
password_hash: newHash,
password_algo: 'argon2id',
});
}
}
return ok;
}
Defina uma janela de sunset de 6 a 12 meses. Mande um e-mail “sua senha está armazenada com um método antigo, faça login para atualizá-la” no marco de 9 meses. Após 12 meses, contas ainda em bcrypt exigem reset de senha forçado no próximo login. Usuários ativos migram de forma transparente; contas inativas pegam um único evento de fricção.
O mesmo padrão funciona para migrar de scrypt ou PBKDF2. O único estado de que você precisa é a coluna password_algo.
Pepper, limites de tamanho e armadilhas de codificação
Algumas arestas afiadas que mordem implantações reais.
Pepper. Um pepper é um segredo no nível da aplicação adicionado a toda senha antes do hash, armazenado separado do banco (em um KMS, variável de ambiente ou Hashicorp Vault). Se o seu banco vazar mas o segredo do app não, os hashes vazados ficam inatacáveis sem o pepper. Aplique-o como HMAC, não por concatenação:
import { createHmac } from 'crypto';
const peppered = createHmac('sha256', process.env.PEPPER).update(password).digest();
const hash = await argon2.hash(peppered, { type: argon2.argon2id, /* ... */ });
Rotacione o pepper raramente (exige re-hash), mas suporte rotação versionando-o: PEPPER_V2, com fallback para PEPPER_V1 na verificação.
Limite de 72 bytes do bcrypt. Se você precisa usar bcrypt e quer suportar senhas de tamanho arbitrário, faça pré-hash com SHA-256 e codifique em base64 (evitando bytes NUL embutidos, que o bcrypt também trata de forma inconsistente):
import { createHash } from 'crypto';
const prepped = createHash('sha256').update(password, 'utf8').digest('base64');
const hash = await bcrypt.hash(prepped, 12);
A mesma transformação prepped precisa rodar na verificação. Documente isso no seu código de auth com um comentário gigante; o seu eu do futuro vai agradecer ao seu eu do presente.
Normalização UTF-8. A string "café" pode ser codificada como c-a-f-é (4 codepoints, NFC) ou c-a-f-e + acento agudo combinante (5 codepoints, NFD). Visualmente são idênticas, mas geram hashes diferentes. Sempre normalize para NFC antes do hash:
const normalized = password.normalize('NFC');
Isso morde teclados móveis e copia-cola de PDFs com mais frequência do que você imagina.
Nunca faça pré-hash no cliente. Um hash computado no cliente e enviado ao servidor é a nova senha. Quem ler o seu banco autentica. Faça hash no servidor, ponto. JWTs não mudam isso. Veja Como decodificar um token JWT para o que JWTs autenticam (e o que não autenticam).
Faça benchmark no hardware de produção, não no seu laptop. Um laptop Intel de 13ª geração rodando Argon2id em m=19456, t=2, p=1 termina em uns 35 ms. Os mesmos parâmetros numa instância EC2 t3.small levam mais perto de 180 ms; num Raspberry Pi 4, mais de 600 ms. Pegue o hardware que vai realmente rodar em produção, cronometre 1.000 verifies e ajuste pela mediana. A variância de latência de login por cold-start de containers serverless também merece medição: cold starts em Lambda podem somar 200–800 ms sem relação com o hash.
FAQ
Qual a diferença entre hash de senhas e criptografia?
Hash é mão única: você calcula uma impressão digital de tamanho fixo que não pode ser revertida para recuperar a entrada. Criptografia é mão dupla: com a chave certa, você decifra de volta para o original. Senhas devem ser hasheadas, não criptografadas. Um servidor não deveria conseguir recuperar a senha de nenhum usuário, e assim um vazamento de banco não vira vazamento de credenciais.
Por que não posso simplesmente usar SHA-256 para senhas?
SHA-256 foi feito para velocidade. Uma GPU moderna calcula 22 bilhões de hashes SHA-256 por segundo, ou seja, uma senha de 8 caracteres em minúsculas vinda de um banco vazado cai em minutos. Hashes de senha precisam de três propriedades que faltam ao SHA-256: execução deliberadamente lenta, salt por registro e memory-hardness. O princípio do tradeoff é o mesmo explicado no aviso “Não use MD5 para segurança” do nosso Gerador de Hash MD5, e você pode ler mais sobre como atacantes transformam hashes fracos em texto puro em Entropia de Senhas.
bcrypt ainda é seguro em 2026?
bcrypt em si não foi quebrado. O key schedule baseado em Blowfish continua criptograficamente sólido. O que mudou foi o modelo de ameaça: GPUs e ASICs tornam a falta de memory-hardness do bcrypt uma fraqueza concreta comparada ao Argon2id. A postura da OWASP em 2026 é que bcrypt é aceitável para sistemas legados com cost ≥ 10, mas projetos novos devem escolher Argon2id.
Argon2i vs Argon2d vs Argon2id: qual usar?
Use Argon2id. A RFC 9106 a especifica como a variante recomendada para hash de senhas. Argon2i é independente dos dados (segura contra canais laterais, mas mais fraca contra ataques tradeoff em GPU). Argon2d é dependente dos dados (forte contra GPU, mas vulnerável a canais laterais de cache-timing). Argon2id é um híbrido que entrega as duas propriedades pelo preço de uma.
Como escolho parâmetros do Argon2id para o meu app?
Comece pelo baseline OWASP: m=19456, t=2, p=1. Depois faça benchmark na CPU de produção e ajuste:
- Decida o orçamento de RAM por login (ex.: 50 MiB no pico de concorrência).
- Defina
mnesse valor ou abaixo. - Rode
argon2.hash()em loop e meça o tempo. - Aumente
taté a mediana ficar entre 100 e 500 ms.
Deixe p=1 a menos que você tenha perfilado e saiba que paralelismo de várias pistas ajuda no seu runtime. Para servidores de auth de alto tráfego, viesar para t mais alto e m mais baixo geralmente dá mais folga de RAM.
O que é o limite de 72 bytes do bcrypt e como lidar com frases-passe longas?
bcrypt alimenta a entrada no key schedule do Blowfish, que trunca em 72 bytes. Uma frase-passe de 150 caracteres tem a mesma segurança que seus primeiros 72 bytes; o resto é ignorado. A solução é pré-hashear com SHA-256 (32 bytes) ou SHA-512 (64 bytes), codificar o digest em base64 para evitar bytes NUL e alimentar isso ao bcrypt. Argon2id e scrypt não têm esse limite; aceitam entrada arbitrariamente longa direto.
Posso migrar bcrypt para Argon2 sem forçar reset de senha?
Sim. O padrão é: armazene os dois algoritmos atrás de uma coluna password_algo, despache a verificação para a biblioteca certa e, em todo verify bem-sucedido com bcrypt, refaça imediatamente o hash com Argon2id e atualize a linha. Usuários ativos migram em silêncio dentro do próprio ritmo de login. Defina uma janela de sunset de 6–12 meses para contas inativas e, depois disso, force reset de senha em qualquer registro ainda em bcrypt. O mesmo padrão funciona para qualquer migração entre algoritmos.
PBKDF2 ainda é uma boa escolha em 2026?
Só quando a conformidade FIPS-140 obriga, típico em governo federal, saúde regulada (HIPAA) e certos sistemas financeiros. Use HMAC-SHA-256 como PRF com pelo menos 600.000 iterações. PBKDF2 não é memory-hard, então cai para ataques de GPU mais rápido que Argon2id no mesmo orçamento de latência. Se FIPS não se aplica, escolha Argon2id e pule a ginástica de conformidade.
A resposta de hash de senhas em 2026 é curta: padrão Argon2id com os parâmetros baseline da OWASP, fallback para scrypt se Argon2 não estiver disponível, mantenha bcrypt só onde o legado exigir e reserve PBKDF2 para sistemas presos a FIPS. Combine o hash com salt por registro (toda biblioteca moderna cuida disso automaticamente), um pepper no nível da aplicação armazenado fora do banco e um loop de re-hash dirigido por login que permite subir os fatores de trabalho conforme o hardware avança.
Gere um conjunto representativo de senhas com o Gerador de Senhas Aleatórias, faça benchmark do seu caminho de verify contra a CPU de produção e escreva os parâmetros em um arquivo de constantes para que o próximo engenheiro saiba exatamente o que mexer em 2028. O contexto completo de segurança (TLS, gerenciamento de sessão, rate limiting, MFA) está no nosso guia de Segurança Web Essencial. Escolha hoje o hash certo.