Design: Detecção de Anomalias de Acesso
Status: 📋 Design (não implementado) Pré-requisitos: IP real funcionando (✅), Painel de Sessões Ativas (pendente) Última atualização: 2026-03-08
1. Objetivo
Identificar acessos anômalos (ex: login de estado/país diferente do habitual) e proteger contas comprometidas com notificações progressivas e bloqueio temporário.
2. Fluxo Proposto
Login (verify-otp)
│
├─ Registra sessão em sessoes_ativas (IP real, geo, user_agent, device_fingerprint)
│
├─ Consulta: IPs/localizações distintas nos últimos 30 dias
│ SELECT DISTINCT ip, cidade, estado, pais
│ FROM sessoes_ativas
│ WHERE usuario_id = X AND criado_em > NOW() - 30 days
│
├─ Baseline do usuário:
│ Padrão normal = 1-3 IPs (casa, escola, celular)
│ Mesma cidade/estado = esperado
│
├─ Se novo IP de estado/país diferente do baseline:
│ Registra anomalia em anomalias_acesso
│ Incrementa contador
│
│ 3-5 anomalias em 30 dias → NOTIFICAÇÃO
│ • Push via ntfy.sh para admin
│ • Notificação in-app para o usuário
│ • Texto: "Detectamos acesso de {cidade}/{estado}. Se não foi você, altere sua senha."
│
│ 5+ anomalias em 30 dias → SOFT-BLOCK
│ • Marca usuario.requer_verificacao = true
│ • Próximo login exige verificação de identidade
│ • Opções para o usuário:
│ 1. Re-validação OTP no telefone cadastrado
│ 2. Confirmar dados pessoais (nome completo + DN)
│ 3. Encerrar todas as sessões ativas
│ • Admin recebe alerta push com dados do incidente
│
└─ Registro em logs_transacoes:
acao: "seguranca.anomalia_detectada" / "seguranca.soft_block_ativado"3. Tabela Proposta: anomalias_acesso
sql
CREATE TABLE anomalias_acesso (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
usuario_id UUID REFERENCES usuarios(id) ON DELETE CASCADE,
ip TEXT NOT NULL,
cidade TEXT,
estado TEXT,
pais TEXT,
user_agent TEXT,
tipo TEXT NOT NULL, -- 'novo_estado', 'novo_pais', 'ip_suspecto'
resolvido BOOLEAN DEFAULT false,
resolvido_em TIMESTAMPTZ,
criado_em TIMESTAMPTZ DEFAULT now()
);4. Métricas de Decisão
| Métrica | Threshold | Ação |
|---|---|---|
| IPs distintos (30 dias) | > 5 | Monitorar |
| Estados distintos (30 dias) | > 2 | Anomalia |
| Países distintos (30 dias) | > 1 | Anomalia grave |
| Anomalias acumuladas (30 dias) | 3-5 | Notificação |
| Anomalias acumuladas (30 dias) | 5+ | Soft-block |
5. Dependências
| Componente | Status | Necessário para |
|---|---|---|
IP real via X-OLP-Client-IP | ✅ Implementado | Dados confiáveis de geolocalização |
sessoes_ativas (tabela) | ❌ Pendente | Baseline de IPs por usuário |
| Painel de Sessões Ativas (UI) | ❌ Pendente | Gestão de sessões pelo usuário |
| Verificação de identidade | ❌ Pendente | Desbloqueio pós soft-block |
anomalias_acesso (tabela) | ❌ Pendente | Registro de anomalias |
6. Notas de Implementação
- A análise de anomalias deve rodar no login (verify-otp), não em cron, para resposta imediata
- O soft-block NÃO impede login — apenas exige uma etapa extra de verificação
- IPs de VPNs corporativas e redes escolares (NAT) devem ser tratados com cuidado — agrupar por
cidade/estadoem vez de IP individual - A janela de 30 dias é suficiente para capturar sazonalidade (ex: viagem) sem gerar falsos positivos
7. Referências
docs/security/IP_RETENTION_LGPD.md— Política de retenção e captura de IP realdocs/plans/SESSION_MANAGEMENT_ALERTS.md— Plano do Painel de Sessões Ativassupabase/functions/_shared/logging-helper.ts—extractIP()comx-olp-client-ip