`P@ssw0rd1` passa na sua validação. Esse é o problema.
O que o NIST mudou em 2024 sobre senhas: comprimento bate complexidade, leet speak está no rockyou.txt e rotação obrigatória enfraquece senhas.
Seu formulário de cadastro exige maiúscula, número e símbolo, comprimento mínimo de 8 caracteres. O usuário digita Senha@2024, passa na validação, entra no banco e aparece no próximo vazamento. Você implementou exatamente o que os tutoriais ensinam — e criou uma política que produz senhas predizíveis.
O que realmente faz uma senha forte não é o que a maioria dos validadores verifica. O NIST atualizou suas diretrizes em 2024 e inverteu boa parte do consenso que o setor inteiro ainda implementa por padrão.
Por que comprimento bate complexidade
Entropia de senha mede a quantidade de aleatoriedade — quanto maior, mais combinações um atacante precisa testar. O ponto que a maioria dos artigos não explica de forma clara: aumentar o comprimento adiciona entropia exponencialmente. Aumentar o conjunto de caracteres, linearmente.
Uma senha de 8 caracteres com letras minúsculas tem 26⁸ ≈ 200 bilhões de combinações. Adicionar maiúsculas sobe para 52⁸ ≈ 53 trilhões — aumento de 200x. Mas passar de 8 para 12 caracteres com só minúsculas dá 26¹² ≈ 95 quatrilhões — aumento de 450.000x.
A consequência prática: uma senha de 16 caracteres aleatórios em minúsculas é incomparavelmente mais difícil de quebrar por força bruta do que P@ssw0rd!123, independentemente dos caracteres especiais. Comprimento é a variável que mais importa, não o conjunto de caracteres.
A ilusão do leet speak
Trocar a por @, e por 3, o por 0 parece adicionar complexidade. Para um humano, parece. Para um programa de quebra de senha, não.
O rockyou.txt — o arquivo de senhas vazadas mais usado em ataques de dicionário — tem 14 milhões de entradas. P@ssw0rd, S3nh@123, @dm1n estão todos lá. As ferramentas de cracking modernas aplicam regras de substituição leet automaticamente sobre qualquer lista de dicionário. password → p@ssword → p@55w0rd → P@55w0rd! é uma transformação que o hashcat executa sem configuração adicional.
Substituição de caracteres não adiciona entropia real porque segue padrões predizíveis. Um usuário que converte minhasenha em m1nh@s3nh@ pensa que criou algo único. O atacante testa essa variação como parte do fluxo normal.
O que o NIST mudou em 2024
A publicação SP 800-63-4 do NIST, atualizada em 2024, é a referência que o setor deveria estar usando. O que ela diz — e que contradiz o que a maioria dos sistemas ainda implementa:
Comprimento mínimo: 8 caracteres obrigatório, 15 recomendado. O máximo deve suportar pelo menos 64 caracteres. Sistemas que truncam senha em 20 ou 32 caracteres estão ativamente impedindo senhas seguras.
Regras de complexidade não são obrigatórias. O NIST não recomenda exigir maiúsculas, números ou símbolos. A razão é exatamente o efeito Senha@2024: quando você força complexidade, os usuários criam padrões previsíveis para satisfazer o validador. O resultado é um conjunto menor de senhas reais do que pareceria.
Rotação periódica obrigatória foi removida. Trocar senha a cada 90 dias não aumenta segurança — diminui. Usuários submetidos a rotação frequente usam Senha@Jan2025, Senha@Abr2025, Senha@Jul2025. É estatisticamente pior do que manter uma senha aleatória longa indefinidamente. Rotação só deve ser exigida quando há evidência de comprometimento.
Verificação contra listas de senhas comprometidas é recomendada. Em vez de regras de complexidade, verifique se a senha aparece em vazamentos conhecidos. A API do Have I Been Pwned permite isso sem enviar a senha em texto claro — usando k-anonymity com os primeiros 5 caracteres do hash SHA-1.
O que a validação deveria verificar de fato
Traduzindo as diretrizes do NIST para código:
async function validarSenha(senha) {
// 1. Comprimento — a variável que mais importa
if (senha.length < 12) {
return { valida: false, motivo: 'Mínimo 12 caracteres' };
}
// 2. Sem repetição excessiva (aaaa, 1111, abababab)
if (/(.)\1{3,}/.test(senha)) {
return { valida: false, motivo: 'Evite sequências repetidas' };
}
// 3. Verificar contra senhas comprometidas via HIBP (k-anonymity)
const hash = await crypto.subtle.digest('SHA-1', new TextEncoder().encode(senha));
const hashHex = Array.from(new Uint8Array(hash))
.map(b => b.toString(16).padStart(2, '0'))
.join('')
.toUpperCase();
const prefix = hashHex.slice(0, 5);
const suffix = hashHex.slice(5);
const res = await fetch(`https://api.pwnedpasswords.com/range/${prefix}`);
const body = await res.text();
const comprometida = body.split('\n').some(linha => linha.startsWith(suffix));
if (comprometida) {
return { valida: false, motivo: 'Essa senha apareceu em vazamentos conhecidos' };
}
return { valida: true };
}
O que esse código não verifica: se tem maiúscula, se tem símbolo, se tem número. Porque não precisa. Uma senha de 16 caracteres aleatórios em minúsculas é mais segura do que Senha@2024! em qualquer métrica que importe.
O que você provavelmente não quer é exigir a chamada à HIBP em toda tentativa de login — só no cadastro e na troca de senha é suficiente.
Rotação obrigatória: a conta que não fecha
Se você ainda tem um sistema que exige troca de senha a cada 30, 60 ou 90 dias, o efeito colateral medido em estudos é consistente: os usuários incrementam. Marco@2024 vira Marco@2025 com uma troca de data. O comprimento não aumenta, a aleatoriedade não aumenta, e o atacante que obteve a senha anterior consegue derivar a próxima com alta probabilidade.
A política de rotação fazia sentido quando a principal ameaça era alguém com acesso físico anotando senhas. Contra credential stuffing em escala e ataques de dicionário automatizados, ela é ineficaz e cria atrito real para o usuário sem contrapartida de segurança.
Exija rotação quando houver evidência de comprometimento — vazamento detectado, acesso suspeito nos logs, ou o próprio usuário reportando. Não como política de calendário.
O que realmente move a agulha
Três coisas, em ordem de impacto.
Comprimento. Uma senha de 20+ caracteres gerada aleatoriamente é inquebrável por força bruta com hardware atual. Não importa se tem símbolo ou não.
Gerenciador de senhas. A única forma de ter senhas longas, únicas e aleatórias em dezenas de serviços sem memorizar nenhuma. Bitwarden é open source e gratuito. Isso resolve o problema humano que nenhum validador resolve.
MFA. Mesmo que a senha vaze — e em algum momento vai, pelo lado de algum serviço que você usa — o segundo fator impede o acesso. É a camada que compensa a falha humana inevitável.
Regras de complexidade são a ilusão de controle. Elas fazem o formulário parecer mais seguro sem tornar as senhas dos seus usuários significativamente mais difíceis de quebrar.
Nota: o conteúdo editorial acabou aqui. O que vem abaixo é uma indicação de ferramenta relacionada ao tema do post.
Ferramenta relacionada
Para gerar senhas com comprimento real e aleatoriedade criptográfica, o Gerador de Senhas usa crypto.getRandomValues — sem enviar nada para servidor, sem cadastro. Útil para demonstrar para usuários o que uma senha gerada de verdade parece.
- 01 diff antes de abrir PR: o hábito que reduz comentários de revisão Ler o próprio diff antes de abrir um PR muda o que você vê no código. Como e por que esse hábito reduz ciclos de revisão e melhora a qualidade dos PRs.
- 02 Convertendo CSV gigantes para JSON sem travar a aba Streams, Web Workers e um truque de chunking que mantém o conversor responsivo mesmo com 200MB de dados.