Plano de Segurança da Informação — Cataloga-ai
Versão: 1.0
Data: 2026-04-25
Responsável: Cyber Head
Stack: Supabase self-hosted, Vercel, Redis, Asaas, GPTMaker, WhatsApp Cloud API
1. Política de Senhas
Requisitos Obrigatórios
Comprimento e Complexidade:
- Mínimo: 14 caracteres
- Obrigatório: pelo menos 1 maiúscula, 1 minúscula, 1 número, 1 caractere especial
- Proibido: senhas que apareçam nos top 10.000 senhas vazadas (ex:
Password123!,Admin@2024) - Proibido: dados pessoais identificáveis (nome, email, data nascimento)
- Força mínima: score 3/4 no
zxcvbn(biblioteca padrão)
Rotação:
- Contas administrativas: rotação obrigatória a cada 90 dias
- Contas usuário final (lojistas): recomendado 180 dias, obrigatório se houver suspeita de comprometimento
- Tokens de API: rotação a cada 180 dias (automática via job cron)
Armazenamento:
- Algoritmo:
bcryptcom cost factor 12 (Supabase Auth padrão) - Nunca armazenar plaintext ou hash reversível
- Salt único por senha (automático no bcrypt)
Como Implementar
No Supabase Auth:
-- Configurar política de senha forte no Supabase Auth
-- Em /supabase/config.toml:
[auth]
minimum_password_length = 14
password_required_characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
Validação no Frontend (Vercel Edge Functions):
import zxcvbn from 'zxcvbn';
export function validatePassword(password: string): { valid: boolean; errors: string[] } {
const errors: string[] = [];
if (password.length < 14) {
errors.push('Senha deve ter no mínimo 14 caracteres');
}
if (!/[a-z]/.test(password)) errors.push('Falta letra minúscula');
if (!/[A-Z]/.test(password)) errors.push('Falta letra maiúscula');
if (!/[0-9]/.test(password)) errors.push('Falta número');
if (!/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password)) {
errors.push('Falta caractere especial');
}
const strength = zxcvbn(password);
if (strength.score < 3) {
errors.push(`Senha muito fraca (score ${strength.score}/4)`);
}
return { valid: errors.length === 0, errors };
}
Lista de senhas proibidas:
- Baixar
10k-most-common.txtdo repositório SecLists - Armazenar hash SHA-256 da lista em Redis para lookup rápido
- Validar no signup e password change
Ferramentas Recomendadas:
zxcvbn(strength meter frontend)haveibeenpwned.com API(check se senha vazou — k-anonymity mode)Supabase Auth(gerenciamento nativo com bcrypt)
2. Política de Acesso (Least-Privilege)
Princípios
- Acesso mínimo necessário: usuário só acessa o que precisa para sua função
- Zero trust: sempre autenticar, sempre autorizar
- MFA obrigatório para contas administrativas
- Segregação de ambientes: dev/staging/prod com credenciais distintas
Roles e Permissões
Supabase (PostgreSQL RLS)
Roles principais:
anon— acesso público (só leitura em tabelas públicas)authenticated— lojista logado (lê/escreve seus próprios dados)service_role— backend trusted (Vercel Edge Functions com chave secreta)admin— operações administrativas (SRE, suporte N3)
Row Level Security (RLS):
-- Exemplo: lojista só acessa seus próprios produtos
CREATE POLICY "Lojistas veem apenas seus produtos"
ON produtos
FOR SELECT
TO authenticated
USING (auth.uid() = lojista_id);
-- Exemplo: consumidor final não acessa diretamente tabela de pedidos
CREATE POLICY "Consumidores não acessam pedidos diretamente"
ON pedidos
FOR ALL
TO anon
USING (false);
MFA Obrigatório:
- Todos admins (
adminrole) devem ativar TOTP MFA no Supabase Auth - Enforce via hook no login:
// Vercel Edge Function — middleware de MFA enforcement
export async function middleware(req: Request) {
const user = await supabase.auth.getUser();
const isAdmin = user.app_metadata.role === 'admin';
const hasMFA = user.app_metadata.mfa_enabled;
if (isAdmin && !hasMFA) {
return new Response('MFA obrigatório para admins', { status: 403 });
}
}
Vercel (Projetos e Ambientes)
Ambientes:
production— acesso restrito (SRE + CTO)preview— acesso dev teamdevelopment— acesso livre dev team
Variáveis de ambiente sensíveis:
- Nunca commitar no Git
- Gerenciar via Vercel Dashboard ou CLI com role-based access
- Secrets específicos por ambiente (não compartilhar prod secrets em preview)
Ferramentas:
- Vercel Teams (role: Owner, Member, Viewer)
- MFA obrigatório para Owners
Redis
Autenticação:
- Senha forte (32 chars alfanuméricos + especiais)
- TLS obrigatório para conexões (mesmo em VPC privada)
- ACL (Access Control List) para segregar namespaces por serviço
Exemplo ACL Redis 6+:
# User para Vercel Edge Functions (só cache de sessão)
ACL SETUSER vercel_edge on >SenhaForte123! ~session:* +get +set +del
# User para worker de jobs (só filas)
ACL SETUSER worker_jobs on >OutraSenha456! ~queue:* +rpush +blpop +llen
# Admin (full access)
ACL SETUSER admin on >AdminSecure789! ~* &* +@all
Ferramentas:
redis-cli ACL(nativo Redis 6+)- Monitoramento:
redis_exporter(Prometheus) para detectar tentativas de autenticação falhadas
Como Implementar MFA
Supabase Auth:
// Ativar MFA para um usuário
const { data, error } = await supabase.auth.mfa.enroll({
factorType: 'totp',
});
// Verificar MFA no login
const { data, error } = await supabase.auth.mfa.challenge({
factorId: data.id,
});
const { data: verifyData, error: verifyError } = await supabase.auth.mfa.verify({
factorId: data.id,
challengeId: challengeData.id,
code: '123456', // código do app TOTP
});
Apps TOTP recomendados:
- Authy (multi-device sync)
- Google Authenticator
- 1Password (integração com password manager)
Fallback (recovery codes):
- Gerar 10 códigos de uso único no momento do enroll
- Armazenar em local seguro (password manager)
- Expirar após uso ou após 1 ano
3. Backup + Disaster Recovery
Requisitos
RTO (Recovery Time Objective): 4 horas
RPO (Recovery Point Objective): 1 hora (máximo perda de dados tolerável)
Estratégia de Backup
PostgreSQL (Supabase Self-Hosted)
Frequência:
- Full backup: diário às 02:00 UTC
- Incremental backup: a cada 1 hora (WAL archiving)
- Snapshot de volume: a cada 6 horas (se rodando em cloud com block storage)
Retenção:
- Full backups: 30 dias
- Incrementais: 7 dias
- Snapshots: 14 dias
- Backups mensais: 1 ano (primeiro domingo de cada mês)
Onde armazenar:
- Primário: S3-compatible storage (ex: Backblaze B2, Cloudflare R2, AWS S3)
- Secundário: cópia offsite em região diferente (ex: S3 us-east-1 → replica para eu-west-1)
- Criptografia: AES-256 server-side encryption (SSE)
Ferramentas:
pg_basebackup(full backup)wal-goupgBackRest(WAL archiving + incremental)- Script de automação:
#!/bin/bash
# /opt/scripts/postgres-backup.sh
set -euo pipefail
BACKUP_DIR="/backups/postgres"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
S3_BUCKET="s3://cataloga-ai-backups-prod"
# Full backup
pg_basebackup -h localhost -U postgres -D "$BACKUP_DIR/$TIMESTAMP" -Ft -z -P
# Upload para S3
aws s3 sync "$BACKUP_DIR/$TIMESTAMP" "$S3_BUCKET/postgres/$TIMESTAMP/" \
--sse AES256 \
--storage-class STANDARD_IA
# Limpar backups locais > 7 dias
find "$BACKUP_DIR" -type d -mtime +7 -exec rm -rf {} +
# Log
echo "Backup concluído: $TIMESTAMP" >> /var/log/postgres-backup.log
Cron:
0 2 * * * /opt/scripts/postgres-backup.sh
Redis
Frequência:
- RDB snapshot: a cada 1 hora
- AOF (Append-Only File): habilitado com
fsync everysec
Configuração redis.conf:
# RDB
save 3600 1
save 300 100
save 60 10000
# AOF
appendonly yes
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
Backup de RDB/AOF:
#!/bin/bash
# /opt/scripts/redis-backup.sh
REDIS_DATA="/var/lib/redis"
BACKUP_DIR="/backups/redis"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
# Trigger BGSAVE
redis-cli BGSAVE
# Aguardar conclusão
while [ $(redis-cli LASTSAVE) -eq $LAST_SAVE ]; do
sleep 1
done
# Copiar RDB
cp "$REDIS_DATA/dump.rdb" "$BACKUP_DIR/dump-$TIMESTAMP.rdb"
# Upload S3
aws s3 cp "$BACKUP_DIR/dump-$TIMESTAMP.rdb" \
"s3://cataloga-ai-backups-prod/redis/dump-$TIMESTAMP.rdb" \
--sse AES256
Vercel (Edge Functions + Configuração)
Código:
- Git é backup primário (GitHub com branches protegidas)
- Commits assinados (GPG)
- Proteção de branch
main: require pull request reviews
Configuração (Variáveis de Ambiente):
- Export semanal via Vercel CLI:
vercel env pull .env.production.backup
gpg --encrypt --recipient admin@cataloga-ai.com.br .env.production.backup
aws s3 cp .env.production.backup.gpg s3://cataloga-ai-backups-prod/vercel/
Restore Testing
Frequência: mensal (primeira segunda-feira de cada mês)
Procedimento:
- Provisionar ambiente de staging isolado
- Restaurar último full backup do PostgreSQL
- Aplicar WAL incrementais até ponto específico no tempo (PITR)
- Validar integridade:
- Contagem de registros por tabela
- Queries de sanidade (ex:
SELECT COUNT(*) FROM usuarios WHERE criado_em > NOW() - INTERVAL '7 days') - Verificar foreign keys e constraints
- Testar restore do Redis (carregar RDB, validar keys críticas)
- Documentar tempo de restore e issues encontrados
- Destruir ambiente de teste
SLA de Restore:
- PostgreSQL full restore: < 2 horas para 100GB
- Redis restore: < 15 minutos
- Vercel redeploy: < 10 minutos
Ferramentas:
pgBackRest(PITR restore)pg_restore(restore de dump)- Script de validação pós-restore
4. Criptografia
Nota: Esta seção foi desenvolvida em colaboração com o Cryptography Counsel para garantir conformidade com melhores práticas criptográficas.
Em Trânsito (TLS)
Requisitos:
- TLS 1.3 obrigatório (ou TLS 1.2 com ciphers fortes se cliente legado)
- Proibido: TLS 1.0, TLS 1.1, SSLv3
- Perfect Forward Secrecy (PFS) obrigatório
- Certificados válidos (Let's Encrypt ou CA confiável)
Configuração Nginx (Supabase Self-Hosted):
server {
listen 443 ssl http2;
server_name api.cataloga-ai.com.br;
ssl_protocols TLSv1.3 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
ssl_prefer_server_ciphers on;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
# HSTS (15768000 = 6 meses)
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" always;
ssl_certificate /etc/letsencrypt/live/api.cataloga-ai.com.br/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.cataloga-ai.com.br/privkey.pem;
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/api.cataloga-ai.com.br/chain.pem;
location / {
proxy_pass http://localhost:3000;
}
}
Verificação:
# Testar ciphers
nmap --script ssl-enum-ciphers -p 443 api.cataloga-ai.com.br
# SSL Labs (online)
# https://www.ssllabs.com/ssltest/analyze.html?d=api.cataloga-ai.com.br
Alvo: A+ no SSL Labs
Redis TLS:
# redis.conf
tls-port 6380
port 0
tls-cert-file /etc/redis/tls/redis.crt
tls-key-file /etc/redis/tls/redis.key
tls-ca-cert-file /etc/redis/tls/ca.crt
tls-protocols "TLSv1.2 TLSv1.3"
Em Repouso (AES-256)
PostgreSQL (Supabase)
Opções:
- Disk encryption (LUKS):
# Criptografar volume de dados
cryptsetup luksFormat /dev/sdb
cryptsetup luksOpen /dev/sdb postgres_data
mkfs.ext4 /dev/mapper/postgres_data
mount /dev/mapper/postgres_data /var/lib/postgresql
- PostgreSQL pgcrypto (column-level):
-- Para campos ultra-sensíveis (CPF, cartão de crédito)
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- Inserir dados criptografados
INSERT INTO usuarios (nome, cpf_encrypted)
VALUES ('João', pgp_sym_encrypt('12345678901', 'chave-secreta-do-vault'));
-- Ler dados
SELECT nome, pgp_sym_decrypt(cpf_encrypted::bytea, 'chave-secreta-do-vault') AS cpf
FROM usuarios;
Recomendação: LUKS para proteção de volume + pgcrypto para campos PII críticos.
Backups
- Criptografia server-side no S3:
--sse AES256(gerenciado pela AWS) - Ou client-side:
gpg --encryptantes de upload
# Exemplo GPG
tar czf - /backups/postgres/$TIMESTAMP | \
gpg --encrypt --recipient backup@cataloga-ai.com.br | \
aws s3 cp - s3://cataloga-ai-backups-prod/postgres/$TIMESTAMP.tar.gz.gpg
Secrets Management
Proibido:
- Secrets em código-fonte (Git)
- Secrets em variáveis de ambiente plaintext (logs podem vazar)
- Secrets hardcoded em Dockerfiles
Permitido:
- HashiCorp Vault (recomendado para prod):
# Armazenar secret
vault kv put secret/cataloga-ai/prod/database password="SuperSecurePass123!"
# Ler secret (em runtime)
export DB_PASSWORD=$(vault kv get -field=password secret/cataloga-ai/prod/database)
- Vercel Environment Variables (com criptografia nativa):
- Configurar via Dashboard ou CLI
- Secrets são criptografados at-rest pela Vercel
- Acesso via
process.env.SECRET_NAMEem edge functions
- Doppler (alternativa SaaS):
- Sync automático com Vercel, GitHub Actions
- Versionamento de secrets
- Audit log de acessos
Key Rotation (ver próxima seção para detalhes):
- Secrets devem ser rotacionados a cada 180 dias
- Automação via Vault + cron job
Ferramentas Recomendadas
- TLS: Let's Encrypt (cert-bot), Nginx/Caddy
- Disk encryption: LUKS (Linux), BitLocker (Windows Server)
- Secrets: HashiCorp Vault (self-hosted ou HCP), Doppler (SaaS)
- Column-level: pgcrypto (PostgreSQL nativo)
- Monitoring: SSL Labs,
testssl.sh
5. Gestão de Chaves
Princípios
- Nunca em código: chaves nunca commitadas no Git
- Segregação: chaves de dev ≠ staging ≠ prod
- Rotação regular: minimizar janela de exploração se vazar
- Acesso auditado: log de quem acessou qual chave, quando
Onde Armazenar Chaves
| Tipo de Chave | Onde Armazenar | Rotação |
|---|---|---|
| Database password | Vault (prod) / Vercel Env Vars (edge functions) | 180 dias |
| Redis password | Vault | 180 dias |
| API keys (Asaas, GPTMaker) | Vault / Vercel Env Vars | 180 dias |
| JWT signing key (Supabase) | Vault | 365 dias |
| Encryption keys (pgcrypto) | Vault (nunca em DB) | 365 dias |
| TLS private keys | Servidor (permission 600, root-only) | Renovação cert (90 dias Let's Encrypt) |
| GPG keys (backup encryption) | Password manager (1Password Team) | 2 anos |
Rotação de Chaves
Senha do PostgreSQL
Procedimento:
- Gerar nova senha forte (32 chars)
NEW_PASSWORD=$(openssl rand -base64 32)
- Atualizar senha no PostgreSQL
ALTER USER cataloga_ai_prod WITH PASSWORD 'nova-senha-aqui';
- Atualizar Vault
vault kv put secret/cataloga-ai/prod/database password="$NEW_PASSWORD"
- Atualizar Vercel Env Vars (se Vercel acessa DB diretamente)
vercel env add DATABASE_PASSWORD production
# Colar nova senha quando solicitado
- Restart gradual de serviços (zero-downtime)
- Edge functions pegam novo env var no próximo deploy
- Supabase Auth pega do Vault no próximo restart (ou via hot-reload se suportado)
- Validar conectividade
psql "postgresql://cataloga_ai_prod:$NEW_PASSWORD@localhost:5432/cataloga_ai"
- Revogar senha antiga (já feito no passo 2, mas confirmar)
API Keys de Terceiros (Asaas, GPTMaker, WhatsApp)
Asaas:
- Gerar nova API key no dashboard Asaas
- Testar em staging
- Atualizar Vault/Vercel
- Deploy
- Revogar chave antiga no dashboard Asaas após 24h (janela de grace)
WhatsApp Cloud API:
- Token gerado no Meta Business Manager
- Rotação: gerar novo token, substituir, revogar antigo
- Frequência: 180 dias ou se suspeita de comprometimento
JWT Signing Key (Supabase Auth)
Atenção: rotacionar esta chave invalida todas sessões ativas.
Procedimento (maintenance window):
- Anunciar manutenção (15min downtime ou force logout)
- Gerar nova chave
NEW_JWT_SECRET=$(openssl rand -base64 64)
- Atualizar
config.tomldo Supabase:
[auth]
jwt_secret = "nova-chave-aqui"
- Restart Supabase Auth
- Todos usuários precisam fazer login novamente
- Comunicar via email/in-app notification
Frequência: anual ou em caso de vazamento
Revogação de Chaves
Gatilhos:
- Funcionário com acesso sai da empresa (revogação imediata)
- Suspeita de comprometimento (vazamento em log, código público)
- Auditoria de segurança recomenda
Checklist de Revogação:
- Identificar todas chaves acessíveis pela pessoa/sistema comprometido
- Gerar novas chaves para substituição
- Atualizar secrets em Vault/Vercel
- Deploy atômico (ou maintenance window se breaking)
- Revogar chaves antigas em sistemas terceiros (dashboards de API)
- Validar que serviços continuam funcionando
- Documentar incidente em log de auditoria
Auditoria de Acesso a Chaves
Vault Audit Log:
# Habilitar audit log no Vault
vault audit enable file file_path=/var/log/vault-audit.log
# Consultar quem acessou um secret
grep "secret/cataloga-ai/prod/database" /var/log/vault-audit.log
Vercel:
- Logs de acesso a env vars disponíveis no dashboard (Team → Activity)
- Monitorar eventos de
env var accessed,env var updated
Alertas:
- Acesso a secrets de prod fora de horário comercial → notificar Security team
- Múltiplas tentativas de acesso falhadas → possível ataque, bloquear IP
Ferramentas
- Vault: HashiCorp Vault (auto-unseal com AWS KMS ou Google Cloud KMS em prod)
- Password Manager: 1Password Teams (para GPG keys e recovery codes)
- Rotação automática:
vault-secrets-operator(Kubernetes) ou cron script customizado
6. Logs de Auditoria
O Que Logar
Eventos de Autenticação
- Login bem-sucedido (user_id, IP, user-agent, timestamp)
- Login falhado (username tentado, IP, motivo: senha errada / MFA falhado / conta bloqueada)
- Logout
- MFA enroll / MFA disable
- Password reset solicitado
- Password reset concluído
- Criação de conta
- Exclusão de conta
Eventos de Acesso a Dados
- Consulta a dados pessoais (queries em tabelas com PII:
usuarios,pedidos,pagamentos) - Download de relatórios com dados sensíveis
- Export de dados (ex: lojista exporta lista de clientes)
- Alteração de dados pessoais (UPDATE em campos PII)
- Exclusão de dados (DELETE — direito ao esquecimento)
Eventos de Mutação Crítica
- Criação/edição de produtos (lojista_id, produto_id, timestamp, diff de campos)
- Criação de pedidos
- Atualização de status de pedido (pendente → pago → enviado)
- Transações de pagamento (Asaas callback: payment_id, status, valor)
- Integração com GPTMaker (prompt enviado, resposta recebida, user_id)
- Opt-in/Opt-out WhatsApp (LGPD compliance: evidência de consentimento)
Eventos Administrativos
- Acesso a painéis admin (SRE, suporte N3)
- Alteração de permissões (role change: lojista → admin)
- Criação de API keys
- Rotação de secrets
- Deploy de código (commit hash, deployer, ambiente)
Formato de Log (JSON estruturado)
Exemplo:
{
"timestamp": "2026-04-25T21:45:32.123Z",
"event_type": "auth.login.success",
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"email": "lojista@example.com",
"ip_address": "203.0.113.42",
"user_agent": "Mozilla/5.0 ...",
"session_id": "abc123",
"mfa_used": true,
"country_code": "BR",
"severity": "info"
}
{
"timestamp": "2026-04-25T21:50:15.456Z",
"event_type": "data.access.pii",
"user_id": "admin-user-id",
"action": "SELECT",
"table": "usuarios",
"query_hash": "sha256-of-query",
"rows_affected": 1,
"ip_address": "10.0.1.5",
"severity": "warning",
"reason": "Suporte N3 acessou dados de usuário para investigação de bug"
}
Onde Armazenar Logs
Stack de Logging:
- Aplicação → stdout/stderr (Vercel Edge Functions, Supabase)
- Collector: Vector.dev ou Fluent Bit (agregação + parsing)
- Storage:
- Hot (últimos 30 dias): Elasticsearch ou Loki (queries rápidas)
- Warm (31-90 dias): S3 + Athena (queries SQL sob demanda)
- Cold (90 dias - 7 anos): S3 Glacier (compliance LGPD, baixo custo)
Configuração Vector.dev:
# /etc/vector/vector.toml
[sources.vercel_logs]
type = "http"
address = "0.0.0.0:8080"
encoding = "json"
[sources.supabase_logs]
type = "file"
include = ["/var/log/supabase/*.log"]
encoding = "json"
[transforms.parse_audit]
type = "remap"
inputs = ["vercel_logs", "supabase_logs"]
source = '''
.timestamp = parse_timestamp!(.timestamp, "%Y-%m-%dT%H:%M:%S%.fZ")
.severity = downcase!(.severity)
if .event_type == "auth.login.failed" {
.alert = true
}
'''
[sinks.elasticsearch]
type = "elasticsearch"
inputs = ["parse_audit"]
endpoints = ["http://localhost:9200"]
index = "cataloga-ai-audit-%Y.%m"
compression = "gzip"
[sinks.s3_archive]
type = "aws_s3"
inputs = ["parse_audit"]
bucket = "cataloga-ai-audit-logs"
key_prefix = "year=%Y/month=%m/day=%d/"
compression = "gzip"
encoding.codec = "json"
Retenção
| Tipo de Log | Retenção Hot | Retenção Total | Justificativa |
|---|---|---|---|
| Auth events | 30 dias | 2 anos | LGPD Art. 37: evidência de consentimento e acesso |
| Data access (PII) | 30 dias | 7 anos | Auditoria de compliance + investigações futuras |
| Mutations críticas | 90 dias | 7 anos | Rastreabilidade de transações financeiras |
| Application logs (debug) | 7 dias | 30 dias | Troubleshooting; sem PII |
| Admin actions | 90 dias | 5 anos | Auditoria interna + investigações |
Monitoramento de Anomalias
Alertas Automáticos (SIEM):
- Múltiplos logins falhados (brute-force):
- Gatilho: > 5 falhas do mesmo IP em 5 minutos
- Ação: bloquear IP temporariamente (15 min) + notificar Security team
- Login de localização anômala:
- Gatilho: user_id faz login do Brasil e 10 min depois da Rússia
- Ação: forçar re-autenticação + MFA challenge + alerta
- Acesso em massa a PII:
- Gatilho: query retorna > 1000 registros de tabela com PII
- Ação: log
severity: critical+ notificar DPO
- Mudança de role para admin:
- Gatilho: qualquer UPDATE em tabela
usuariosque mude role paraadmin - Ação: alerta imediato + exigir aprovação de 2 admins (workflow manual)
- Download de dump de banco:
- Gatilho:
pg_dumpexecutado fora de janela de backup (02:00 UTC ± 30 min) - Ação: alerta crítico + investigar imediatamente
Ferramentas SIEM:
- Open-source: Wazuh (agente + manager + Kibana dashboard)
- SaaS: Datadog Security Monitoring, Sumo Logic
- Custom: ElastAlert (rules em YAML, envia para Slack/PagerDuty)
Exemplo ElastAlert Rule:
# /etc/elastalert/rules/brute_force_login.yaml
name: Brute Force Login Attempt
type: frequency
index: cataloga-ai-audit-*
num_events: 5
timeframe:
minutes: 5
filter:
- term:
event_type: "auth.login.failed"
query_key: "ip_address"
alert:
- slack
slack_webhook_url: "https://hooks.slack.com/services/YOUR/WEBHOOK"
slack_title: "🚨 Brute Force Detected"
slack_text: |
IP: {0}
Failed logins: {1} in 5 minutes
Integridade de Logs (Proteção Contra Adulteração)
Problema: atacante com acesso root pode modificar logs para ocultar rastros.
Solução:
- Forward-only logging: logs enviados para collector remoto em tempo real (atacante não tem acesso)
- Assinatura de logs: cada linha de log recebe hash SHA-256 encadeado
- Append-only storage: S3 com versionamento + Glacier Vault Lock (imutável)
Exemplo de Hash Encadeado:
{
"timestamp": "2026-04-25T22:00:00.000Z",
"event_type": "auth.login.success",
"user_id": "user-123",
"log_hash": "sha256-of-this-log-entry",
"previous_log_hash": "sha256-of-previous-entry"
}
Se atacante alterar uma linha, previous_log_hash da próxima linha não baterá → adulteração detectada.
Ferramentas Recomendadas
- Collector: Vector.dev (Rust, performance), Fluent Bit (lightweight)
- Storage: Elasticsearch (queries) + S3 (archive)
- SIEM: Wazuh (open-source), Datadog, Sumo Logic
- Alertas: ElastAlert, Grafana Alerts, PagerDuty
- Visualização: Kibana (Elastic Stack), Grafana
7. Hardening de Servidor (Supabase Self-Hosted)
Princípios
- Minimizar superfície de ataque: desabilitar serviços desnecessários
- Firewall restritivo: só portas essenciais abertas
- Atualizações regulares: patches de segurança aplicados em < 48h (critical) / < 7 dias (high)
- Monitoramento ativo: detectar intrusões em tempo real
Configuração de Portas e Firewall
Portas Necessárias:
| Serviço | Porta | Origem Permitida | Protocolo |
|---|---|---|---|
| PostgreSQL | 5432 | VPC interna apenas (10.0.0.0/8) | TCP |
| Redis | 6379/6380 (TLS) | VPC interna | TCP |
| Supabase API (Kong) | 443 | Internet (público) | HTTPS |
| Supabase Studio (admin) | 3000 | VPN ou IPs de escritório | HTTPS |
| SSH | 22 | IPs de SRE apenas (whitelist) | TCP |
| Prometheus exporter | 9100 | Monitoring server | TCP |
Firewall (iptables):
#!/bin/bash
# /etc/iptables/rules.v4
# Flush existente
iptables -F
# Políticas padrão
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# Permitir loopback
iptables -A INPUT -i lo -j ACCEPT
# Permitir conexões estabelecidas
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# SSH (só de IPs autorizados)
iptables -A INPUT -p tcp --dport 22 -s 203.0.113.10 -j ACCEPT # IP do SRE 1
iptables -A INPUT -p tcp --dport 22 -s 203.0.113.11 -j ACCEPT # IP do SRE 2
# HTTPS (público)
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# PostgreSQL (só VPC)
iptables -A INPUT -p tcp --dport 5432 -s 10.0.0.0/8 -j ACCEPT
# Redis TLS (só VPC)
iptables -A INPUT -p tcp --dport 6380 -s 10.0.0.0/8 -j ACCEPT
# Rate limiting (anti-DDoS básico)
iptables -A INPUT -p tcp --dport 443 -m state --state NEW -m recent --set
iptables -A INPUT -p tcp --dport 443 -m state --state NEW -m recent --update --seconds 1 --hitcount 20 -j DROP
# Log de DROP (debug)
iptables -A INPUT -j LOG --log-prefix "iptables-dropped: " --log-level 4
# Salvar
iptables-save > /etc/iptables/rules.v4
Firewall alternativo (UFW - mais simples):
# Resetar
ufw --force reset
# Padrão deny
ufw default deny incoming
ufw default allow outgoing
# SSH (whitelist)
ufw allow from 203.0.113.10 to any port 22 proto tcp
ufw allow from 203.0.113.11 to any port 22 proto tcp
# HTTPS
ufw allow 443/tcp
# PostgreSQL (VPC)
ufw allow from 10.0.0.0/8 to any port 5432 proto tcp
# Habilitar
ufw enable
Atualizações de OS
Sistema: Ubuntu Server 22.04 LTS (ou 24.04 LTS)
Política:
- Critical security patches: aplicar em < 48h
- High/Medium patches: aplicar em < 7 dias
- Low patches: janela de manutenção mensal
Automação (unattended-upgrades):
# Instalar
apt install unattended-upgrades
# Configurar /etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
};
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
Unattended-Upgrade::MinimalSteps "true";
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:00"; # 3am UTC
Monitoramento de patches pendentes:
# Verificar updates disponíveis
apt list --upgradable
# Verificar apenas security
apt-cache policy | grep -i security
Alerta automático:
# Cron diário
0 8 * * * /usr/lib/update-notifier/apt-check --human-readable | mail -s "Updates disponíveis" sre@cataloga-ai.com.br
Hardening Adicional
Desabilitar Serviços Desnecessários
# Listar serviços rodando
systemctl list-units --type=service --state=running
# Desabilitar exemplos comuns desnecessários
systemctl disable bluetooth.service
systemctl disable cups.service # impressão
systemctl disable avahi-daemon.service # Zeroconf
Kernel Hardening (sysctl)
# /etc/sysctl.d/99-hardening.conf
# Proteção contra IP spoofing
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# Ignorar ICMP redirects (anti-MITM)
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
# Desabilitar source routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
# Proteção SYN flood
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
# Log de pacotes suspeitos
net.ipv4.conf.all.log_martians = 1
# Aplicar
sysctl -p /etc/sysctl.d/99-hardening.conf
SSH Hardening
# /etc/ssh/sshd_config
# Desabilitar root login direto
PermitRootLogin no
# Só key-based auth (sem senha)
PasswordAuthentication no
ChallengeResponseAuthentication no
# Protocolo 2 apenas (1 é inseguro)
Protocol 2
# Limitar usuários
AllowUsers sre-user1 sre-user2
# Port alternativo (obscurity, não segurança real, mas ajuda contra bots)
Port 2222
# Idle timeout
ClientAliveInterval 300
ClientAliveCountMax 2
# Reiniciar SSH
systemctl restart sshd
Fail2Ban (Anti Brute-Force)
# Instalar
apt install fail2ban
# Configurar /etc/fail2ban/jail.local
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5
[sshd]
enabled = true
port = 2222
logpath = /var/log/auth.log
[nginx-limit-req]
enabled = true
filter = nginx-limit-req
logpath = /var/log/nginx/error.log
maxretry = 3
# Iniciar
systemctl enable fail2ban
systemctl start fail2ban
Monitoramento de Intrusões (IDS)
AIDE (Advanced Intrusion Detection Environment):
# Instalar
apt install aide
# Inicializar baseline
aideinit
# Verificar mudanças (diário via cron)
aide --check | mail -s "AIDE Report" sre@cataloga-ai.com.br
OSSEC (Host-based IDS):
- Monitora logs de sistema, alterações de arquivo, rootkits
- Alertas em tempo real para Slack/Email
Ferramentas Recomendadas
- Firewall: UFW (simples) ou iptables (avançado)
- Patch management: unattended-upgrades (Ubuntu)
- IDS: OSSEC, Wazuh
- SSH hardening: Fail2Ban
- File integrity: AIDE
- Benchmark: CIS Benchmark for Ubuntu (checklist de hardening)
8. Vulnerability Management
Processo de Scan Periódico
Frequência:
- Infraestrutura (OS, serviços): semanal
- Aplicação (código, dependências): a cada commit (CI/CD) + diário (scheduled)
- Dependências (npm, pip): diário
- Penetration test externo: anual (contratado via empresa terceira)
Ferramentas de Scan
Scan de Infraestrutura
OpenVAS (Open Vulnerability Assessment System):
# Instalar via Docker
docker run -d -p 443:443 --name openvas mikesplain/openvas
# Acessar https://localhost:443
# Criar target: api.cataloga-ai.com.br
# Rodar scan completo semanal
Nmap (network scan):
# Scan de portas abertas
nmap -sS -sV -O api.cataloga-ai.com.br
# Scan de vulnerabilidades (scripts NSE)
nmap --script vuln api.cataloga-ai.com.br
Scan de Aplicação
OWASP ZAP (Dynamic Application Security Testing - DAST):
# Rodar via Docker
docker run -t owasp/zap2docker-stable zap-baseline.py \
-t https://staging.cataloga-ai.com.br \
-r zap-report.html
# Revisar relatório
# Gatilho: falhar CI/CD se severity >= High
Trivy (Container scan):
# Scan de imagem Docker do Supabase
trivy image supabase/postgres:15
# Scan de filesystem
trivy fs /var/lib/postgresql
Scan de Dependências
npm audit (Node.js):
# No projeto Vercel Edge Functions
npm audit --production
# Fix automático (cuidado com breaking changes)
npm audit fix
# CI/CD: falhar build se critical/high
npm audit --audit-level=high
Dependabot (GitHub):
- Habilitar no repositório
- Auto-cria PRs para atualizar dependências vulneráveis
- Revisar e mergear em < 48h (critical), < 7 dias (high)
Snyk (SaaS - alternativa):
# Instalar CLI
npm install -g snyk
# Autenticar
snyk auth
# Scan
snyk test
# Monitor contínuo
snyk monitor
Scan de Secrets (Leaked Credentials)
Gitleaks (secrets no Git):
# Scan de repositório
gitleaks detect --source . --verbose
# Pre-commit hook (prevenir commits com secrets)
# .git/hooks/pre-commit:
#!/bin/bash
gitleaks protect --staged --verbose --redact
TruffleHog (scan de histórico completo):
trufflehog git https://github.com/cataloga-ai/backend --only-verified
Classificação de Severidade
| Severity | CVSS Score | Patching SLA | Ação |
|---|---|---|---|
| Critical | 9.0 - 10.0 | 24 horas | Patch imediato, hotfix se necessário, comunicar stakeholders |
| High | 7.0 - 8.9 | 7 dias | Patch na próxima janela de manutenção, revisar mitigações temporárias |
| Medium | 4.0 - 6.9 | 30 dias | Incluir em roadmap de patches mensais |
| Low | 0.1 - 3.9 | 90 dias | Revisar em ciclo trimestral |
Exceções: se vulnerabilidade não é explorável no nosso contexto (ex: Windows vulnerability em servidor Linux), pode ser marcada como wontfix com justificativa.
Workflow de Patching
- Detecção: Scan automático identifica CVE-2024-XXXXX em pacote
libssl1.1 - Triagem: Security team avalia severidade (CVSS score) e exploitabilidade
- Priorização: Se critical, escala para SRE imediatamente; se high/medium, agenda
- Teste: Aplicar patch em ambiente de staging, validar que não quebra aplicação
- Deploy: Aplicar em produção (com rollback plan se der ruim)
- Verificação: Re-scan para confirmar que vulnerabilidade foi remediada
- Documentação: Registrar em ticket de patching (Jira/Linear) com CVE ID, ação tomada, timestamp
Mitigações Temporárias (Quando Patch Não Está Disponível)
Exemplos:
- Firewall: bloquear endpoint vulnerável via iptables/WAF
- Rate limiting: limitar requests para impedir exploração em massa
- Upgrade intermediário: usar versão beta com fix se stable não saiu ainda
- Desabilitar feature: se feature vulnerável não é crítica, desabilitar temporariamente
Responsible Disclosure (Recebimento de Vulnerabilidades Externas)
Canal: security@cataloga-ai.com.br
Página pública: https://cataloga-ai.com.br/security.txt (RFC 9116)
Contact: mailto:security@cataloga-ai.com.br
Expires: 2027-12-31T23:59:59.000Z
Preferred-Languages: pt-BR, en
Canonical: https://cataloga-ai.com.br/.well-known/security.txt
Processo:
- Researcher reporta vulnerabilidade por email
- Security team confirma recebimento em < 24h
- Triagem: reproduzir + avaliar impacto
- Fix: desenvolver patch (SLA conforme severidade)
- Validação: testar com researcher se possível
- Deploy: aplicar em produção
- Disclosure: após fix, publicar advisory (opcional: Hall of Fame para researcher)
- Recompensa: se programa de bug bounty, pagar conforme tabela
Bug Bounty (Futuro):
- Plataforma: HackerOne, Bugcrowd, ou in-house
- Scope:
*.cataloga-ai.com.brexcetostaging.(fora de scope) - Payouts: Critical $2000, High $1000, Medium $500, Low $100 (ajustar conforme orçamento)
Compliance e Auditoria
Relatórios mensais:
- Vulnerabilidades detectadas (breakdown por severidade)
- Tempo médio de patching por severidade
- Dependências desatualizadas (aging)
- Top 5 CVEs mais críticos resolvidos no mês
Dashboard (Grafana):
# Métrica Prometheus: vulnerabilities_detected_total{severity="critical"}
sum(vulnerabilities_detected_total{severity="critical"}) by (service)
KPIs:
- Mean Time to Patch (MTTP): Critical < 24h, High < 7 dias
- % de dependências atualizadas: > 95%
- Cobertura de scan: 100% de servidores + 100% de repos
Ferramentas Recomendadas
| Camada | Ferramenta | Tipo | Custo |
|---|---|---|---|
| Infraestrutura | OpenVAS | Open-source | Grátis |
| Infraestrutura | Nessus | Comercial | $$ |
| Aplicação (DAST) | OWASP ZAP | Open-source | Grátis |
| Aplicação (SAST) | SonarQube | Open-source/Comercial | Grátis/$$$ |
| Container | Trivy | Open-source | Grátis |
| Dependências | Dependabot | Grátis (GitHub) | Grátis |
| Dependências | Snyk | SaaS | $ (free tier) |
| Secrets | Gitleaks | Open-source | Grátis |
| Pen Test | Externos | Serviço | $$$ (anual) |
9. Anexos
Checklist de Implementação
- [ ] 1. Política de Senhas
- [ ] Configurar
minimum_password_length = 14no Supabase Auth - [ ] Implementar validação com
zxcvbnno frontend - [ ] Integrar lista de senhas proibidas (10k common passwords)
- [ ] Configurar rotação automática de tokens a cada 180 dias
- [ ] 2. Política de Acesso
- [ ] Implementar Row Level Security (RLS) em todas tabelas com PII
- [ ] Habilitar MFA obrigatório para contas admin
- [ ] Configurar ACL no Redis com users segregados
- [ ] Revisar roles do Vercel (Owner/Member/Viewer)
- [ ] 3. Backup + Disaster Recovery
- [ ] Configurar
pg_basebackupdiário (cron 02:00 UTC) - [ ] Configurar WAL archiving com
wal-goupgBackRest - [ ] Configurar Redis RDB snapshots (hourly) + AOF
- [ ] Testar restore em staging (mensal)
- [ ] Documentar RTO/RPO alcançados
- [ ] 4. Criptografia
- [ ] Validar TLS 1.3 no Nginx (SSL Labs A+)
- [ ] Configurar LUKS no volume PostgreSQL
- [ ] Implementar
pgcryptopara campos ultra-sensíveis (CPF, cartão) - [ ] Migrar secrets para HashiCorp Vault
- [ ] Habilitar TLS no Redis
- [ ] 5. Gestão de Chaves
- [ ] Migrar todas passwords para Vault
- [ ] Criar procedimento de rotação de chaves (runbook)
- [ ] Agendar rotação trimestral (cron job)
- [ ] Habilitar Vault audit log
- [ ] 6. Logs de Auditoria
- [ ] Implementar logging estruturado (JSON) em Vercel Edge Functions
- [ ] Configurar Vector.dev para coletar logs
- [ ] Deploy Elasticsearch para hot storage (30 dias)
- [ ] Configurar S3 archive (7 anos)
- [ ] Criar alertas ElastAlert (brute-force, acesso anômalo)
- [ ] 7. Hardening de Servidor
- [ ] Configurar UFW/iptables (só portas essenciais)
- [ ] Habilitar
unattended-upgrades - [ ] Aplicar kernel hardening (sysctl)
- [ ] Hardening SSH (key-only, PermitRootLogin no)
- [ ] Instalar Fail2Ban
- [ ] 8. Vulnerability Management
- [ ] Configurar OpenVAS scan semanal
- [ ] Habilitar Dependabot no GitHub
- [ ] Implementar
npm auditno CI/CD (fail on high/critical) - [ ] Configurar Trivy scan em imagens Docker
- [ ] Criar
security.txte publicar canal de responsible disclosure - [ ] Documentar SLA de patching (24h critical, 7d high)
Responsáveis
| Seção | Implementador | Revisor | Deadline Sugerido |
|---|---|---|---|
| 1-2 (Auth + Access) | Backend Lead | Cyber Head | Sprint 1 (2 semanas) |
| 3 (Backup) | SRE Lead | Cyber Head | Sprint 1 |
| 4-5 (Crypto + Keys) | Cryptography Counsel | Cyber Head | Sprint 2 (2 semanas) |
| 6 (Logs) | Backend Lead + SRE | Cyber Head | Sprint 2 |
| 7 (Hardening) | SRE Lead | Cyber Head | Sprint 3 (1 semana) |
| 8 (Vuln Mgmt) | DevSecOps | Cyber Head | Sprint 3 |
Custos Estimados (Mensal)
| Item | Ferramenta | Custo Mensal |
|---|---|---|
| Secrets Management | HashiCorp Vault Cloud (Starter) | $40 |
| Logging | Elasticsearch (3 nodes, 50GB) | $120 |
| S3 Archive (500GB) | AWS S3 Glacier | $2 |
| SIEM | Wazuh (self-hosted) | $0 |
| Vulnerability Scan | OpenVAS + Trivy (self-hosted) | $0 |
| Dependabot | GitHub (incluído) | $0 |
| Backup Storage | Backblaze B2 (1TB) | $5 |
| Total | ~$167/mês |
Custo anual de Pen Test externo: $3.000 - $5.000 (1x/ano)
Revisão e Atualização
- Frequência de revisão deste plano: trimestral
- Responsável: Cyber Head
- Gatilhos de atualização fora do ciclo:
- Incidente de segurança
- Mudança significativa de stack (novo serviço)
- Nova regulação aplicável (ex: ANPD publica norma técnica)
Documento aprovado por:
[ ] Cyber Head
[ ] Cryptography Counsel (seção 4)
[ ] CTO
[ ] DPO (validação de compliance LGPD)
Próxima revisão agendada: 2026-07-25