Políticas de senha e recuperação de conta no back-end

Capítulo 10

Tempo estimado de leitura: 9 minutos

+ Exercício

Políticas de senha pragmáticas (o que realmente melhora a segurança)

Uma política de senha eficaz equilibra três objetivos: reduzir senhas fracas (fáceis de adivinhar), diminuir reutilização (senhas já vazadas) e manter boa usabilidade (para não incentivar comportamentos ruins, como anotar senha ou criar padrões previsíveis). No back-end, isso se traduz em validações no momento de criação/alteração de senha e em mecanismos de recuperação de conta que não abram brechas.

Tamanho mínimo e limites razoáveis

  • Comprimento mínimo: prefira 12 caracteres como padrão. Se o seu público tem fricção alta (ex.: mobile), 10 pode ser aceitável, mas compense com checagem de vazamentos e bloqueio de senhas comuns.
  • Comprimento máximo: defina um máximo (ex.: 72 ou 128) para evitar abuso de recursos e compatibilidade com algoritmos de hash. Se usar bcrypt, lembre que ele considera apenas os primeiros 72 bytes; então, valide e normalize para não criar falsas expectativas.
  • Permitir espaços e Unicode: passphrases com espaços são boas. Se aceitar Unicode, normalize (ex.: NFKC) para evitar confusões visuais e inconsistências.

Bloqueio de senhas comuns e padrões óbvios

Em vez de exigir “1 maiúscula, 1 número, 1 símbolo” (que gera senhas previsíveis), bloqueie diretamente o que é fraco:

  • Listas de senhas comuns (ex.: top 10k/100k).
  • Senhas contendo o e-mail/username, nome do produto, ou partes do nome do usuário.
  • Padrões repetitivos (ex.: aaaaaa, 123123123) e sequências simples (abcdef, qwerty).

Verificação contra vazamentos (credential stuffing prevention “na origem”)

Além de bloquear senhas comuns, verifique se a senha já apareceu em vazamentos conhecidos. A ideia é impedir que o usuário escolha uma senha que já está em bases de credenciais expostas. Isso pode ser feito consultando um serviço de “breached password” (idealmente com um método que não envie a senha em texto puro; use abordagem de prefixo/consulta parcial ou um provedor interno).

Recomendação prática: se a senha estiver vazada, recuse com mensagem genérica do tipo “senha fraca” e, se possível, explique que ela já foi exposta em incidentes.

Regras a evitar (requisitos contraproducentes)

  • Troca periódica obrigatória sem evidência de comprometimento: aumenta reutilização e padrões previsíveis (ex.: Senha@2025 vira Senha@2026).
  • Regras rígidas de composição (maiúscula/número/símbolo obrigatórios): tendem a reduzir entropia real e piorar a experiência.
  • Bloquear colar/gerenciadores: incentive gerenciadores de senha; não bloqueie paste.

Exemplo de validação de senha (checklist de back-end)

  • Normalizar entrada (ex.: trim apenas se sua política não permitir espaços nas pontas; caso permita, não remova).
  • Validar tamanho mínimo/máximo.
  • Checar lista de senhas comuns.
  • Checar vazamentos.
  • Checar se contém identificadores do usuário (e-mail, username).
  • Registrar métricas (sem logar a senha), para calibrar política.
// Pseudocódigo de validação (não logar senha!){  "minLen": 12,  "maxLen": 72,  "checks": [    "length",    "notCommonPassword",    "notBreached",    "notContainEmailOrUsername"  ]}

Fluxo de reset de senha (token com expiração, uso único e armazenamento seguro)

Reset de senha é um dos fluxos mais sensíveis: ele precisa ser resistente a vazamento de token, replay (reuso), e enumeração de usuários. A abordagem recomendada é: gerar um token aleatório de alta entropia, armazenar apenas o hash do token no banco, aplicar expiração curta, marcar como usado e invalidar sessões/tokens após a troca.

Continue em nosso aplicativo e ...
  • Ouça o áudio com a tela desligada
  • Ganhe Certificado após a conclusão
  • + de 5000 cursos para você explorar!
ou continue lendo abaixo...
Download App

Baixar o aplicativo

Modelo de dados sugerido

CampoDescrição
idIdentificador do reset
user_idUsuário alvo
token_hashHash do token (ex.: SHA-256 do token + pepper opcional)
expires_atExpiração (ex.: 15–60 min)
used_atTimestamp de uso (nulo se não usado)
created_atAuditoria
request_ipOpcional: auditoria/risco
request_uaOpcional: auditoria/risco

Passo a passo: solicitar reset

  1. Entrada: usuário informa e-mail (ou username).
  2. Resposta uniforme: sempre responder com sucesso genérico, independentemente de o usuário existir.
  3. Se existir: criar registro de reset com expiração curta e token aleatório.
  4. Armazenar hash do token (não o token em si).
  5. Enviar link por e-mail contendo o token (e um identificador do reset, se desejar).

Geração de token: use bytes aleatórios criptograficamente seguros (ex.: 32 bytes) e codifique em Base64URL/hex. Exemplo conceitual:

token = base64url(randomBytes(32))tokenHash = sha256(token + PEPPER)store(tokenHash, userId, expiresAt)

Exemplo de request/response seguro: solicitar reset

Request

POST /v1/auth/password/reset/requestContent-Type: application/json{  "email": "ana@example.com"}

Response (uniforme)

200 OKContent-Type: application/json{  "message": "Se existir uma conta para este e-mail, enviaremos instruções para redefinir a senha."}

Passo a passo: confirmar reset (trocar a senha)

  1. Entrada: token (e opcionalmente um reset_id), e a nova senha.
  2. Validar: expiração, não usado, e comparar token_hash com hash do token recebido.
  3. Aplicar política de senha: tamanho, comum, vazada, etc.
  4. Marcar como usado (uso único) e trocar a senha do usuário.
  5. Invalidar sessões/tokens existentes do usuário após a troca (ex.: incrementando um token_version no usuário, ou revogando sessões no servidor).
  6. Responder sem detalhes excessivos (não revelar se token era válido vs. usuário inexistente, quando possível).

Exemplo de request/response: confirmar reset

Request

POST /v1/auth/password/reset/confirmContent-Type: application/json{  "token": "mYk9p7m0cY...base64url...",  "new_password": "minha frase longa com 4 palavras"}

Response

200 OKContent-Type: application/json{  "message": "Senha atualizada com sucesso."}

Erros seguros (sem vazar sinal útil)

Quando o token for inválido/expirado/usado, evite mensagens que ajudem um atacante a testar tokens. Use respostas genéricas e códigos coerentes:

400 Bad Request{  "error": {    "code": "INVALID_RESET_TOKEN",    "message": "Não foi possível redefinir a senha. Solicite um novo link."  }}

Detalhes importantes de implementação

  • Uso único: marque used_at no mesmo fluxo transacional da troca de senha para evitar race conditions.
  • Expiração curta: 15–60 minutos. Para maior segurança, 15–30.
  • Hash do token: se o banco vazar, tokens não podem ser usados diretamente. SHA-256 é comum para token aleatório; opcionalmente adicione pepper do servidor.
  • Não reutilizar token: ao solicitar novo reset, você pode invalidar resets anteriores (ex.: apagar/expirar todos os resets pendentes do usuário) para reduzir superfície.
  • Auditoria: registre eventos (solicitação, confirmação, falha) sem dados sensíveis.

Confirmação de e-mail e alteração de e-mail

Confirmação de e-mail e mudança de e-mail são fluxos que também exigem tokens de uso único e expiração. O objetivo é garantir que o usuário controla o endereço informado e reduzir risco de sequestro de conta via troca de e-mail.

Confirmação de e-mail (após cadastro)

Estratégia: gerar token de verificação, armazenar hash, enviar link. Ao confirmar, marcar email_verified_at.

Request para reenviar confirmação (resposta uniforme):

POST /v1/auth/email/verification/requestContent-Type: application/json{  "email": "ana@example.com"}
200 OK{  "message": "Se existir uma conta para este e-mail, enviaremos um link de verificação."}

Confirmar verificação:

POST /v1/auth/email/verification/confirmContent-Type: application/json{  "token": "..."}
200 OK{  "message": "E-mail verificado com sucesso."}

Alteração de e-mail (fluxo recomendado)

  • Exigir autenticação para iniciar a troca.
  • Confirmar no e-mail novo: enviar token para o novo endereço e só efetivar após confirmação.
  • Notificar o e-mail antigo: enviar alerta “se não foi você, proteja sua conta”.
  • Opcional: exigir reautenticação recente (ex.: senha/2º fator) para ações sensíveis.

Passo a passo: solicitar mudança de e-mail

  1. Usuário autenticado envia new_email.
  2. Back-end cria um registro de “pending email change” com token e expiração.
  3. Envia link para o novo e-mail com token.
  4. Envia notificação para o e-mail antigo informando a tentativa.

Request

POST /v1/account/email/change/requestAuthorization: Bearer <access_token>Content-Type: application/json{  "new_email": "ana.novo@example.com"}

Response

200 OK{  "message": "Se o e-mail puder ser usado, enviaremos um link de confirmação para o novo endereço."}

Confirmar mudança de e-mail

Request

POST /v1/account/email/change/confirmContent-Type: application/json{  "token": "..."}

Response

200 OK{  "message": "E-mail atualizado com sucesso."}

Cuidados específicos na alteração de e-mail

  • Evitar enumeração: se new_email já estiver em uso, não revele diretamente. Responda de forma uniforme e trate internamente.
  • Bloquear troca para e-mails descartáveis (opcional, conforme produto).
  • Invalidar sessões/tokens após troca de e-mail (ação sensível), ou ao menos exigir novo login em dispositivos não confiáveis.

Proteção contra enumeração de usuários (mensagens uniformes e tempos consistentes)

Enumeração acontece quando um atacante consegue descobrir se um e-mail/usuário existe a partir de diferenças na resposta. Para reduzir isso:

  • Mensagens uniformes em endpoints como: solicitar reset, reenviar verificação, iniciar troca de e-mail.
  • Status code consistente: frequentemente 200 OK mesmo quando não existe conta.
  • Tempo de resposta: evite diferenças grandes (ex.: retornar instantâneo quando não existe e demorar quando existe). Você pode introduzir pequenas esperas uniformes ou tornar o caminho “não existe” semelhante (sem fazer operações caras).
  • Não expor campos como “e-mail não cadastrado” em validações públicas.

Exemplos de respostas uniformes

Solicitar reset

200 OK{  "message": "Se existir uma conta para este e-mail, enviaremos instruções para redefinir a senha."}

Reenviar verificação

200 OK{  "message": "Se existir uma conta para este e-mail, enviaremos um link de verificação."}

Iniciar troca de e-mail (autenticado)

200 OK{  "message": "Se o e-mail puder ser usado, enviaremos um link de confirmação para o novo endereço."}

Checklist de segurança para políticas de senha e recuperação

  • Senha: mínimo 12, máximo definido, permitir passphrases, bloquear comuns, checar vazamentos, evitar regras rígidas de composição.
  • Reset: token aleatório, hash no banco, expiração curta, uso único, invalidar sessões/tokens após troca.
  • E-mail: confirmação com token hash + expiração; mudança de e-mail com confirmação no novo e notificação no antigo.
  • Enumeração: mensagens e status uniformes, cuidado com timing e com detalhes em erros.
  • Auditoria: registrar eventos (solicitação/uso) sem dados sensíveis; monitorar volume anormal.

Agora responda o exercício sobre o conteúdo:

Ao implementar o fluxo de redefinição de senha no back-end, qual combinação de medidas reduz o risco de vazamento do token, replay e enumeração de usuários?

Você acertou! Parabéns, agora siga para a próxima página

Você errou! Tente novamente.

A abordagem recomendada usa token aleatório com hash armazenado, expiração curta e uso único, além de resposta uniforme para evitar enumeração e invalidação de sessões/tokens após a troca para reduzir impacto de credenciais comprometidas.

Próximo capitúlo

MFA no back-end: visão geral e integração segura

Arrow Right Icon
Capa do Ebook gratuito Autenticação e Autorização no Back-end: Sessões, JWT e Boas Práticas
56%

Autenticação e Autorização no Back-end: Sessões, JWT e Boas Práticas

Novo curso

18 páginas

Baixe o app para ganhar Certificação grátis e ouvir os cursos em background, mesmo com a tela desligada.