Files
eden/docs/security/threat-model.md
Matheus (Handix) 9c14671e19 feat(signatures): UI completa do módulo + rate limiting em rotas públicas
Fecha as duas pendências da leva anterior (módulo de Assinatura
Eletrônica): tela de backoffice para gerenciar envelopes (criação,
envio, cancelamento, checkpoint/finalização, auditoria) e as duas
páginas públicas (/assinar/:token, /verificar/:verificationId).

Backend: novos endpoints de streaming de PDF (documento congelado e
PDF final consolidado, autenticados e via token público) que faltavam
para a UI funcionar — o signatário não tinha como ver o próprio
documento antes de confirmar leitura. Rate limiting (guard próprio,
em memória, chaves por IP e por token) em todas as rotas sem sessão:
auth (login/mfa/forgot-password/reset-password/refresh/logout) e todo
o fluxo público de assinatura/verificação.

Suíte: 77/77 verdes. pnpm turbo run typecheck build: 28/28.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 21:51:18 -03:00

8.2 KiB

EDEN — Threat Model (Fase 0)

Modelo inicial, por bounded context, método STRIDE simplificado. Revisar a cada fase (§18 do Master Prompt) com o agente eden-security.

1. Ativos críticos

  1. Credenciais de autenticação (senhas, refresh tokens, OTP, tokens de link público/assinatura).
  2. Dados pessoais PF/PJ (CPF/CNPJ, endereço, contatos) — LGPD.
  3. Segredos de integração (Focus NFe, SaperX, Control iD, SMTP, S3, chaves de IA) — sempre cifrados em repouso (AES-256-GCM), chave raiz fora do banco.
  4. Registros financeiros/fiscais (títulos, faturas, documentos fiscais emitidos) — integridade e auditabilidade.
  5. Cadeia de auditoria de assinatura eletrônica (hash-chain) — valor probatório/legal.
  6. Dado bruto de ponto (AFD) — valor legal, imutabilidade.
  7. Dump de backup do Postgres (contém tudo acima) — acesso altamente restrito.

2. Superfícies de ataque e mitigação por camada

2.1 Rotas públicas sem autenticação

Existem por necessidade de negócio (cadastro de cliente/revenda, assinatura eletrônica, verificação pública, ViaCEP/CNPJ lookup client-side). Mitigação obrigatória em toda rota pública nova:

  • Token opaco ≥96 bits de entropia como capacidade de acesso, nunca sequencial/adivinhável.
  • Rate limiting por IP e por token/identidade quando aplicável (duas dimensões, nunca uma só).
  • Revalidação total de regra de negócio no backend — o cliente é sempre não confiável.
  • 404/409 sem vazar existência de recurso quando aplicável (mensagens genéricas para "não existe" vs. "já usado").

Implementado (2026-09-17): todas as rotas públicas hoje existentes têm rate limiting — apps/api/src/common/rate-limit/ (RateLimiterService em memória, janela fixa; RateLimitGuard + @RateLimit(...) por rota). POST /v1/auth/{login,mfa/challenge,forgot-password,reset-password,refresh,logout} por IP; GET/POST /v1/public-signature/:token/* por IP (balde compartilhado do controller, pega scraping de vários tokens de uma fonte) e por token (pega força bruta de um link vazado vindo de qualquer IP); GET /v1/public-verify/:verificationId por IP e por id. Limites concretos e a razão de cada um em apps/api/src/common/rate-limit/rate-limit-rules.ts. Sem Redis (ainda não existe, ver compose.yaml) — armazenamento local ao processo, correto para a instância única atual (ADR-0002); não sobrevive a múltiplas réplicas do eden-api, revisar quando isso mudar. Testes: apps/api/test/rate-limit.spec.ts.

Risco residual aceito, não coberto por este trabalho: (1) um atacante que gire IPs lentamente ainda opera abaixo do limite por IP indefinidamente — não há lockout por conta a nível de aplicação além do que já existe no OTP de assinatura; (2) app.set('trust proxy', ...) nunca foi configurado — se um reverse proxy/LB externo vier a ficar na frente do eden-api em produção, req.ip (chave do rate limit e de todo log de IP) passará a ver sempre o IP do proxy, não o do cliente real, cegando esta mitigação — configurar isso corretamente (e só isso, um hop confiável) é pré-requisito de qualquer topologia com proxy na frente da API.

2.2 Autenticação e sessão

  • Herdar do legado: token_version-like mecanismo de invalidação global, MAS evoluir para refresh token rotativo hashado (ADR-0003) — não repetir JWT de 30 dias sem revogação.
  • Argon2id (não bcrypt) para novo hash de senha — custo a definir em ADR de segurança/config, revisável sem quebrar hashes existentes (versionamento de parâmetro).
  • MFA/TOTP obrigatório para super_admin/admin assim que o módulo existir.
  • Lockout progressivo por conta + rate limit por IP (duplo, como no legado) — nunca só um dos dois.

2.3 Autorização

  • Nunca confiar em role, customer_id, reseller_id, legal_entity_id vindos do cliente — resolver sempre a partir da sessão/token no servidor.
  • super_admin mantém bypass total mas toda ação sensível permanece auditada (bypass de autorização ≠ bypass de auditoria).
  • Testar isolamento cross-reseller e cross-subscriber explicitamente em CI (casos invariantes do Master Prompt §15.3).

2.4 Dados em trânsito/repouso

  • TLS obrigatório ponta a ponta (terminação em proxy reverso — nunca assumir rede interna "confiável" sem TLS entre containers quando trafegar dado sensível entre hosts distintos; dentro do mesmo compose/host, aceitável por rede docker isolada, mas revisar se algum dia sair para múltiplos hosts).
  • Campos de alto risco (ver Master Prompt §5.4) cifrados com AES-256-GCM, chave raiz via secret manager/env fora do banco, versionamento de chave.
  • Nenhum arquivo (documento, anexo, backup) exposto por URL pública direta — sempre proxy autenticado pelo backend (padrão herdado do legado, preservar).

2.5 Integrações externas (Focus NFe, SaperX, Control iD, n8n)

  • Adapter/port isolado por provider (Master Prompt §13) — nunca acoplar domínio ao payload bruto externo.
  • Timeout + retry com backoff + circuit breaker — indisponibilidade externa nunca corrompe o ERP nem trava a request HTTP do usuário (usar fila/worker).
  • Webhooks sempre autenticados (assinatura HMAC) e idempotentes (event id + delivery log).
  • n8n nunca acessa o Postgres diretamente — só via API/eventos com service accounts escopados.

2.6 Upload de arquivo

  • Validação de MIME real (não só extensão), limite de tamanho por rota, scan hook preparado para malware, armazenamento fora do webroot, nunca executável a partir do storage.

2.7 Geração de documento/PDF

  • Sanitização de HTML em duas camadas (allowlist estrita de tags/atributos/estilos/schemes de URL) antes de qualquer renderização — herdar do legado.
  • Renderer (Chromium/Playwright) sem navegação de rede (page.setContent apenas, bloquear qualquer request de rede) — elimina SSRF por construção, herdar do legado.

2.8 Auditoria

  • Append-only reforçado em nível de banco (trigger que recusa UPDATE/DELETE fora de uma escotilha administrativa explícita e ela própria auditada) — não confiar só em "a aplicação nunca faz UPDATE".
  • Ordem de eventos por sequência monotônica (serial/bigserial), nunca por timestamp (timestamps podem colidir dentro de uma transação).
  • Nunca gravar segredo em claro no audit log (nem em metadata JSON).

2.9 Infraestrutura/containers

  • Postgres nunca exposto publicamente (ver docs/architecture.md §4).
  • Segredos de ambiente via .env/secret store, nunca em imagem de container ou repositório.
  • Cada container roda com usuário não-root quando a imagem base permitir.
  • Backup: dump em streaming (nunca materializado em disco/memória local), acesso de restauração com fricção deliberada (confirmação explícita da chave do backup, como no legado).

3. Casos invariantes de segurança (a testar sempre — Master Prompt §15.3)

  • Desconto pendente nunca vira valor legal aprovado sem approval_status = approved.
  • fidelity_period não aprovado nunca altera vigência/multa/vencimento legal.
  • Mesmo serial/MAC/patrimônio nunca alocado duas vezes simultaneamente.
  • Webhook repetido nunca duplica pagamento; billing run repetido nunca duplica fatura; mesma referência fiscal nunca emite documento fiscal duplicado.
  • Usuário de revenda nunca acessa dado de outra revenda alterando UUID na URL; assinante nunca acessa documento de outro customer account.
  • AFD bruto nunca é alterável por nenhuma rota administrativa.
  • Audit log crítico nunca é mutável pela aplicação em uso normal.

4. LGPD — pontos de atenção específicos

  • Minimização: cadastro público de cliente/revenda já segue esse princípio no legado (só pede o necessário por PF/PJ) — preservar.
  • Direito de exportação/eliminação do titular: não existe hoje no legado — gap a suprir no EDEN, registrar ADR quando o módulo de Identity/Customer 360 for implementado.
  • Retenção configurável: não existe hoje no legado (dados nunca expiram automaticamente) — decisão de produto a tomar com jurídico/DPO da Handix antes da Fase 2, registrar assunção em docs/assumptions.md enquanto isso.

5. Revisão

Este documento deve ser revisitado ao final de cada fase (Master Prompt §18) e sempre que um novo adapter de integração externa for adicionado.