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.
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.
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 assinaturaclaims = 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.
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 } }));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"]},
)http.sessionManagement(s -> s.sessionFixation().migrateSession())
.oauth2ResourceServer(o -> o.jwt(Customizer.withDefaults())); // verifica assinatura, exp e emissor via configuraçãoProve 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.
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 cookieChecklist
- 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.
conexões no mapa
- A06 Insecure Designdefine o fluxo de recuperação deA07 Authentication Failures
- A01 Broken Access Controlprecisa de uma identidade confiável deA07 Authentication Failures
- A04 Cryptographic Failuresprotege as credenciais deA07 Authentication Failures
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…