A09 Security Logging and Alerting Failures
Você não consegue responder ao que não consegue ver. Logs sem alertas são um arquivo morto; alertas sem bons logs são ruído. Ambos precisam existir, e nenhum pode ser injetável nem estar cheio de segredos.
O que é
Esta categoria cobre logging, monitoramento e alertas de segurança ausentes ou ruins: logins e falhas de controle de acesso que não são registrados, logs que ficam apenas na máquina que o atacante controla, eventos sem nenhum alerta por trás e logs que vazam dados sensíveis ou podem ser forjados pela entrada do usuário.
É o A09 no :2025, com um nome que enfatiza o alerta: um log sobre o qual ninguém é acionado não é um controle.
Como o ataque funciona
- Uma rodada de com milhares de logins falhos não é registrada, ou é registrada e nunca revisada.
- Um atacante com acesso inicial apaga os logs locais; sem cópia central, o rastro desaparece.
- : um nome de usuário contendo uma quebra de linha escreve uma linha falsa de "login com sucesso".
- Os logs registram senhas, tokens ou números de cartão, transformando o repositório de logs no alvo mais rico.
Código vulnerável
Logging de texto livre com entrada bruta do usuário, um segredo na mensagem e nenhum registro da falha que importa.
def login(email, password):
print(f"login attempt {email} / {password}") # segredo no log, possível injeção de quebra de linha
user = authenticate(email, password)
if not user:
return None # falha não registrada
return userconsole.log("login failed for " + req.body.email + " with token " + req.headers.authorization);A correção
Registre os eventos de segurança como dados estruturados com nomes de campo estáveis: quem, o quê, de onde, resultado e um . Nunca registre segredos; codifique a entrada do usuário para que não possa forjar linhas. Envie os logs para fora do host imediatamente e associe regras de alerta aos eventos que importam (picos de falhas, mudanças de privilégio, acesso negado a objetos sensíveis).
import json, logging
log = logging.getLogger("security")
def event(action, outcome, **fields):
log.info(json.dumps({"action": action, "outcome": outcome, **fields})) # json.dumps faz escape de quebras de linha
def login(email, password, ip, request_id):
user = authenticate(email, password)
if not user:
event("login", "failure", email=email, ip=ip, request_id=request_id) # sem senha, sem token
return None
event("login", "success", user_id=user.id, ip=ip, request_id=request_id)
return userreq.log.warn({ action: "login", outcome: "failure", email: req.body.email, ip: req.ip }, "auth");
// a redaction do pino mantém os segredos fora mesmo que alguém registre o objeto inteiro
const logger = pino({ redact: ["req.headers.authorization", "*.password", "*.token"] });- alert: LoginFailureSpike
expr: sum(rate(auth_events_total{action="login",outcome="failure"}[5m])) > 5
for: 5m
labels: { severity: page }
annotations:
summary: "Falhas de login acima do normal: possível credential stuffing"Prove a correção
Teste que o evento é emitido com os campos certos, que nenhum segredo aparece e que a entrada não consegue forjar uma linha. Depois teste o próprio caminho do alerta: reproduza uma rajada e confirme que alguém é notificado. Um alerta não testado é uma esperança.
def test_failed_login_is_logged_without_secrets(caplog):
with caplog.at_level("INFO", logger="security"):
login("bob@x.io\nlogin success", "hunter2", "203.0.113.9", "req-1")
text = caplog.text
assert "hunter2" not in text # sem segredo
assert text.count("\n") == 1 # a quebra de linha injetada não criou uma linha
assert '"outcome": "failure"' in text
def test_alert_fires_on_burst(alert_harness):
for _ in range(200):
login("bob@x.io", "bad", "203.0.113.9", "r")
assert alert_harness.fired("LoginFailureSpike")Checklist
- Registre: autenticação, falhas de controle de acesso, falhas de validação de entrada, ações privilegiadas e mudanças na configuração de segurança.
- Use um formato estruturado consistente; inclua hora, ator, ação, alvo, resultado, origem e um correlation id.
- Envie os logs rapidamente a um repositório central somente de anexação; restrinja quem pode alterá-los ou apagá-los.
- Não registre segredos, tokens nem números completos de cartão/documento; codifique a entrada não confiável.
- Defina alertas e um responsável para cada um; escreva a resposta em um runbook; teste o caminho do alerta.
- Defina uma retenção que atenda às necessidades legais e de investigação.
conexões no mapa
- A09 Security Logging and Alerting FailuresregistraA10 Mishandling of Exceptional Conditions
- A09 Security Logging and Alerting Failuresdetecta o abuso deA01 Broken Access Control
atualizado em 14/10/2026 · fontes para aprofundar · reportar erro
em outros domínios
- Engenharia de detecçãosecopso log vira detecção versionada
Estude antes
Desbloqueia
teste o que entendeu
Carregando perguntas…