Todos os artigos
74 artigos · atualizado semanalmente Veja nossas Ferramentas
Todos os artigos
Tutoriais

`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.

COVER · Tutoriais

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. passwordp@sswordp@55w0rdP@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.

RD
Autor
Rafael Duarte
Desenvolvedor backend com passagem por fintech e SaaS B2B — trabalhou em times que escalaram APIs de zero a milhões de requisições. Carrega cicatrizes de produção suficientes para ter opiniões fortes sobre ferramentas, padrões e decisões de arquitetura. Não é acadêmico: leu a RFC do UUID quando precisou escolher entre v4 e v7 para uma tabela de alta escrita.
Ver perfil