Threat Modeling com STRIDE em Sprints: Exemplo Completo de Microservico
Como aplicar STRIDE em um microservico real de pagamentos dentro de uma sprint de duas semanas, com diagrama, ameacas priorizadas e mitigacoes acionaveis.
Threat modeling morre na gaveta quando vira reuniao de quatro horas sem dono. Na Basilisk OffSec, integramos STRIDE em sprints de duas semanas com um microservico de pagamentos como cobaia: 1 desenvolvedor backend, 1 SRE, 1 pesquisador ofensivo, 90 minutos no kickoff e 30 minutos de revisao no meio da sprint. O resultado nao e um PDF de 40 paginas, e sim 12 issues no Jira com mitigacoes verificaveis. Este post mostra exatamente como rodamos isso no servico payments-api, que recebe webhooks de PSPs, fala com Postgres, Redis e um KMS, e como cada letra do STRIDE virou patch real no codigo.
Antes de modelar, desenhamos o DFD (Data Flow Diagram) no draw.io com quatro elementos: entidades externas (PSP, frontend), processos (payments-api, worker-reconciliation), datastores (Postgres tx_db, Redis idempotency_cache) e fluxos. Marcamos as trust boundaries: internet -> Cloudflare -> ingress -> mesh interno -> KMS. Esse diagrama nao precisa ser bonito; precisa ser correto. Em 25 minutos tinhamos o DFD aprovado por todos. Quem ja montou um lab de pentest sabe que diagrama errado gera teste errado Pentest Web do Zero: Montando um Lab Seguro com DVWA, Juice Shop e Burp Suite. Aqui vale o mesmo: se o fluxo de webhook nao mostra o HMAC sendo validado antes do parse JSON, voce vai modelar o servico que existe na sua cabeca, nao o que esta em producao.
Spoofing apareceu primeiro no fluxo PSP -> payments-api. O webhook chegava com header X-Signature, mas a verificacao era feita depois do json.loads(body), abrindo janela para parser differential. Mitigacao: validar HMAC SHA-256 com chave rotativa do KMS antes de tocar no body, com comparacao constant-time via hmac.compare_digest. Tampering surgiu no Redis: o cache de idempotencia nao tinha TTL fixo nem assinatura, entao um atacante com acesso a rede interna poderia injetar entradas para causar replay de cobranca. Adicionamos prefixo namespaced + HMAC curto na chave e ACL com requirepass + TLS no Redis 7. Repudiation foi tratada com log append-only em uma tabela audit_log com hash encadeado, padrao que tambem usamos quando documentamos pivoting em redes segmentadas Pivoting com Chisel e Ligolo-ng: Redes Segmentadas em Lab de Pentest.
Information Disclosure virou a categoria com mais achados, oito no total. Stack traces vazavam via 500 do FastAPI em ambiente de homologacao espelhado em prod, secrets apareciam em /debug atras de um header magico esquecido por um estagiario em 2024, e o endpoint /metrics do Prometheus expunha labels com card_bin. Corrigimos com middleware que serializa apenas {error_id, code} para o cliente, removemos /debug, e aplicamos relabel_config no Prometheus dropando labels sensiveis. Para o time entender o impacto, mostramos uma POC equivalente a um SSRF puxando cloud metadata, exercicio que ja documentamos em outro lab SSRF Descomplicado: Explorando Cloud Metadata em Lab AWS Local. Tambem rodamos um SAST com Semgrep custom rules e SCA com osv-scanner; ambos entraram no pipeline como gates bloqueantes para vulnerabilidades High e Critical.
Denial of Service nao foi tratado so como rate limit. Mapeamos amplificacao algoritmica: um endpoint /search aceitava regex do cliente e batia em Postgres com LIKE %term%. Trocamos por tsvector com GIN index e cap de 64 caracteres no termo. Adicionamos token bucket por API key no envoy (100 rps burst 200) e circuit breaker no client do KMS com pybreaker, porque o KMS gerenciado tem cota de 1200 ops/s por chave e ja causamos um incidente de 14 minutos em janeiro. Elevation of Privilege fechou a lista: o JWT da API interna usava HS256 com segredo compartilhado entre 6 servicos. Migramos para RS256 com chave por servico no KMS, claims com aud especifico, e validacao de exp + nbf + iss em middleware unico publicado como biblioteca interna basilisk-authz==2.3.0.
No final da sprint, cada item virou issue com titulo no formato STRIDE-