Política de Retenção de IPs — LGPD + Marco Civil da Internet
Última atualização: 2026-03-08 Base legal: Lei 12.965/2014 (Marco Civil, art. 15) + Lei 13.709/2018 (LGPD, art. 16)
1. Contexto Legal
| Lei | Artigo | Obrigação |
|---|---|---|
| Marco Civil da Internet | Art. 15 | Provedor de aplicações deve guardar registros de acesso por 6 meses |
| LGPD | Art. 16 | Dados pessoais devem ser eliminados após o término do tratamento, salvo obrigação legal |
O IP do usuário é dado pessoal (pode identificar indiretamente). A estratégia concilia ambas as leis:
- 0–6 meses: IP completo armazenado (obrigação legal)
- Após 6 meses: IP anonimizado via hash truncado (LGPD)
2. Implementação
2.1 Onde o IP é armazenado
| Tabela | Campo | Uso |
|---|---|---|
logs_transacoes | ip | Auditoria de todas as operações do sistema |
login_otps | ip_origem | Rate limiting de OTP (TTL: 24h, limpo pelo cron) |
portal_login_tentativas | ip | Rate limiting do portal (TTL: 7 dias, limpo pelo cron) |
2.2 Anonimização Automática (Cron)
A tarefa anonimizarIPsAntigos no maintenance-cron executa diariamente:
logs_transacoes: IPs comcriado_em < NOW() - 6 mesessão substituídos poranon_+ SHA-256 truncado (8 hex chars)- Exemplo:
200.123.45.67→anon_a1b2c3d4 - O prefixo
anon_evita re-processamento - O hash preserva agrupamento (mesmo IP → mesmo hash) sem permitir reversão
- Campos
cidade,estado,paissão mantidos (dados agregados, não pessoais)
- Exemplo:
login_otpseportal_login_tentativas: Já são limpos pelo cron com TTL muito menor (24h e 7 dias), portanto não precisam de anonimização adicional
2.3 Batch Processing
A anonimização processa até 1.000 registros por execução do cron para evitar timeouts. Se houver mais registros pendentes, serão processados na próxima execução diária.
3. Captura de IP Real
3.1 Problema Histórico
Entre 18/jan/2026 e 08/mar/2026, ~72,6% dos logs capturavam o IP do datacenter Cloudflare (2a06:98c0:3600::103) em vez do IP real do cliente. Causa: o header X-Real-IP era sobrescrito pela infraestrutura Supabase.
3.2 Solução: Header Customizado
O Cloudflare Worker (OLP Gateway) injeta o IP real do cliente no header X-OLP-Client-IP, que não é sobrescrito pelo Supabase.
Ordem de prioridade em extractIP():
1. x-olp-client-ip ← Gateway OLP (header customizado, confiável)
2. x-real-ip ← Fallback (pode ser sobrescrito em produção)
3. cf-connecting-ip ← Cloudflare direto (sem Worker)
4. x-forwarded-for ← Padrão proxies (primeiro IP)3.3 Ação Manual Necessária
⚠️ O código do Cloudflare Worker precisa ser atualizado manualmente no painel Cloudflare para injetar
X-OLP-Client-IPem vez de (ou além de)X-Real-IP.
Linha a alterar no Worker:
// ANTES:
forwardHeaders.set('X-Real-IP', clientIP);
// DEPOIS (adicionar):
forwardHeaders.set('X-OLP-Client-IP', clientIP);
forwardHeaders.set('X-Real-IP', clientIP); // manter para compatibilidade4. Verificação
Como validar que IPs estão sendo capturados corretamente
-- IPs reais vs Cloudflare nos últimos 7 dias
SELECT
CASE
WHEN ip LIKE '2a06:98c0:%' THEN 'cloudflare_dc'
WHEN ip LIKE 'anon_%' THEN 'anonimizado'
ELSE 'ip_real'
END as tipo,
COUNT(*)
FROM logs_transacoes
WHERE criado_em > NOW() - INTERVAL '7 days'
GROUP BY tipo;Como validar a anonimização
-- Registros anonimizados
SELECT COUNT(*) FROM logs_transacoes WHERE ip LIKE 'anon_%';
-- Registros ainda com IP real e > 6 meses (devem ser 0 após cron)
SELECT COUNT(*) FROM logs_transacoes
WHERE criado_em < NOW() - INTERVAL '6 months'
AND ip IS NOT NULL
AND ip NOT LIKE 'anon_%';5. Referências
supabase/functions/_shared/logging-helper.ts—extractIP()com prioridadex-olp-client-ipsupabase/functions/maintenance-cron/index.ts— Tarefa 11:anonimizarIPsAntigos()docs/architecture/CLOUDFLARE_WORKER_CODE.md— Código do Worker com header customizadodocs/architecture/CLOUDFLARE_WORKER_GATEWAY.md— Documentação do Gatewaydocs/security/AUDIT_LOG.md— Padrões de logging