pular para o conteúdo
voltar ao mapa
técnica
etapa: code
3 min de leitura

A07 Authentication Failures

O login é a porta da frente. Tentativas ilimitadas, senhas reutilizadas, sessões que nunca expiram e tokens que não são realmente verificados deixam um atacante entrar como um usuário real.

Hydra / ffuf (on systems you own)Have I Been Pwned Passwords APIjwt.io / jwt_toolPasskeys / WebAuthnOWASP ZAPKeycloak / Auth0 / Cognito

O que é

As falhas de autenticação são fraquezas na confirmação da identidade de um usuário ou na gestão da sessão que vem depois: permitir e força bruta, aceitar senhas fracas ou vazadas, expor ids de sessão, pular ou verificar mal os tokens, ou oferecer um fluxo de recuperação fraco.

O :2025 a lista como A07 com o nome Authentication Failures.

Como o ataque funciona

  • Credential stuffing: listas de pares de e-mail e senha vazados de outros sites são reutilizadas em escala contra o seu login.
  • Força bruta e password spraying: umas poucas senhas comuns em muitas contas, abaixo de qualquer bloqueio ingênuo.
  • Tratamento fraco de JWT: o servidor aceita alg: none, nunca verifica a assinatura nem a expiração, ou usa um segredo fácil de adivinhar.
  • e roubo de sessão: o id de sessão não é rotacionado depois do login, viaja na URL, ou o cookie não tem HttpOnly e Secure.
  • Bypass da recuperação de conta: links de redefinição que nunca expiram ou perguntas de segurança com respostas públicas.

Código vulnerável

Sem throttling, uma comparação rápida de um hash sem salt, um id de sessão mantido depois do login e um token que é decodificado mas nunca verificado.

login.js (Express)javascript
app.post("/login", async (req, res) => {
  const user = await db.user.findByEmail(req.body.email);
  if (user && user.passwordHash === sha1(req.body.password)) {
    req.session.userId = user.id;          // mesmo id de sessão de antes do login
    return res.json({ ok: true });
  }
  res.status(401).json({ error: "wrong email or password" });   // tentativas ilimitadas
});

const claims = jwt.decode(token);          // decode() NÃO verifica a assinatura
tokens.pypython
claims = jwt.decode(token, options={"verify_signature": False})

A correção

Aplique throttling por conta e por IP, verifique as senhas com um hash lento, regenere a sessão no login e defina as flags do cookie. Verifique os tokens com um algoritmo fixado, uma chave real e checagens de emissor, audiência e expiração. Quando puder, use passkeys ou um provedor de identidade em vez de construir o login você mesmo, e adicione um segundo fator para contas sensíveis.

login.js (Express)javascript
const limiter = rateLimit({ windowMs: 15 * 60 * 1000, limit: 10, keyGenerator: (r) => `${r.ip}:${r.body?.email}` });

app.post("/login", limiter, async (req, res) => {
  const user = await db.user.findByEmail(req.body.email);
  const ok = user && (await argon2.verify(user.passwordHash, req.body.password));
  if (!ok) return res.status(401).json({ error: "wrong email or password" });   // mesma mensagem nos dois casos
  req.session.regenerate(() => {         // novo id após o login: derrota a fixation
    req.session.userId = user.id;
    res.json({ ok: true });
  });
});

app.use(session({ cookie: { httpOnly: true, secure: true, sameSite: "lax", maxAge: 3600_000 } }));
tokens.py (PyJWT)python
claims = jwt.decode(
    token,
    key=PUBLIC_KEY,
    algorithms=["RS256"],          # fixe o algoritmo; nunca aceite "none"
    audience="api.example.com",
    issuer="https://id.example.com",
    options={"require": ["exp", "iat", "sub"]},
)
SecurityConfig.java (Spring Security)java
http.sessionManagement(s -> s.sessionFixation().migrateSession())
    .oauth2ResourceServer(o -> o.jwt(Customizer.withDefaults()));   // verifica assinatura, exp e emissor via configuração

Prove a correção

Teste os comportamentos dos quais um atacante depende: a décima primeira tentativa é recusada, o id de sessão muda após o login e tokens adulterados ou sem assinatura são rejeitados.

test_auth.py (pytest)python
def test_login_is_throttled(client):
    codes = [client.post("/login", json={"email": "a@x.io", "password": f"guess{i}"}).status_code for i in range(15)]
    assert 429 in codes

def test_session_id_changes_after_login(client, user):
    before = client.get("/").cookies.get("sid")
    client.post("/login", json=user.credentials)
    assert client.cookies.get("sid") != before

def test_unsigned_token_is_rejected(client):
    forged = b64(b'{"alg":"none"}') + "." + b64(b'{"sub":"admin"}') + "."
    assert client.get("/api/me", headers={"Authorization": f"Bearer {forged}"}).status_code == 401

def test_cookie_flags(client, user):
    cookie = client.post("/login", json=user.credentials).headers["set-cookie"]
    assert "HttpOnly" in cookie and "Secure" in cookie

Checklist

  • Aplique e monitore o login por conta, por IP e por dispositivo; adicione atraso progressivo ou desafio, e não apenas bloqueio total (que permite negação de serviço).
  • Verifique as senhas novas contra uma lista de senhas vazadas; exija comprimento em vez de regras arbitrárias de complexidade.
  • Ofereça autenticação multifator, de preferência resistente a phishing (passkeys, ), e exija-a para administradores.
  • Rotacione o id de sessão no login e em mudanças de privilégio; faça-o expirar; invalide-o no logout.
  • Verifique cada token: assinatura, algoritmo, emissor, audiência, expiração. Nunca confie apenas no decode.
  • Torne a recuperação tão forte quanto o login: links de uso único e curta duração; a mesma resposta genérica para e-mails conhecidos e desconhecidos.
Credential stuffingAtaque que testa em massa pares usuário/senha vazados de outros serviços. Assinatura: muitas falhas de login distribuídas por muitos IPs, com poucas tentativas por conta.ver no glossário →OWASP Top 10A lista de referência mais famosa de riscos de segurança em aplicações web (A01 acesso quebrado, A02 falhas criptográficas, A03 injeção...), revisada a cada alguns anos pela comunidade OWASP. É um mapa educacional de categorias de risco — não um checklist de ferramenta nem uma certificação.ver no glossário →Session fixationUm atacante planta um id de sessão conhecido no navegador da vítima; se o app mantém esse id depois do login, o atacante compartilha a sessão. Regenere o id no login.ver no glossário →Rate limitingLimite de requisições por entidade e janela de tempo. A escolha da chave (IP, conta, token, ASN) pesa tanto quanto o valor do limite.ver no glossário →PasskeyWebAuthnUm login resistente a phishing baseado em um par de chaves guardado no dispositivo do usuário; o site guarda apenas a chave pública, então não há senha para roubar ou reutilizar.ver no glossário →

conexões no mapa

atualizado em 14/10/2026 · fontes para aprofundar · reportar erro

em outros domínios

  • Bot managementsecopscredential stuffing é, antes de tudo, tráfego automatizado

Desbloqueia

teste o que entendeu

Carregando perguntas…