Em 1994, quando Gary McGraw e John Viega começaram a trabalhar no que viria a se tornar a disciplina de software security, a pergunta que os guiava era simples e perturbadora: por que times de desenvolvimento conseguem construir sistemas funcionais e corretamente especificados que, ao mesmo tempo, são fundamentalmente inseguros? A resposta que encontraram não era falta de conhecimento de criptografia nem ausência de firewalls — era a ausência de um processo estruturado para pensar em como o sistema poderia ser abusado antes de ser construído. Threat modeling é esse processo.
Threat modeling é a prática de identificar sistematicamente ameaças a um sistema, avaliando sua probabilidade e impacto, e definindo controles antes do código existir. A analogia com arquitetura é precisa: assim como nenhum arquiteto projeta um prédio sem pensar em carga de vento, resistência sísmica e saídas de emergência — não porque esses problemas sejam os mais comuns, mas porque corrigi-los depois é caríssimo — engenheiros sênior não projetam sistemas sem pensar explicitamente em como alguém com intenção maliciosa os abusaria. O timing é tudo: threat modeling feito em design review custa horas; descoberto em pentest custa semanas; descoberto em produção após incidente custa meses e, frequentemente, reputação.
Adam Shostack, que liderou o programa de threat modeling na Microsoft por mais de uma década e depois escreveu Threat Modeling: Designing for Security (Wiley, 2014), articula o objetivo com uma pergunta que deveria ser feita no início de todo projeto: "o que pode dar errado?". Parece simples demais, mas a maioria dos times não faz essa pergunta de forma estruturada. STRIDE é o framework que torna essa pergunta respondível de forma sistemática e com cobertura razoável.
Este conceito cobre os fundamentos de threat modeling com STRIDE: como criar Data Flow Diagrams (DFDs) que capturam o que importa para segurança, como identificar trust boundaries, como aplicar STRIDE por elemento do diagrama, como documentar ameaças e escolher controles, e como fazer threat modeling como prática contínua em vez de evento único de auditoria.
O que faz um threat model ser útil
Um threat model útil responde quatro perguntas: o que estamos construindo, o que pode dar errado, o que vamos fazer a respeito, e se estamos satisfeitos com as escolhas feitas. Shostack as formalizou como o ciclo What / What can go wrong / What are we going to do about it / Did we do a good job. A maioria dos times que tenta fazer threat modeling sem processo estruturado responde apenas a primeira e para aí — um documento de arquitetura disfarçado de threat model.
O artefato central de um threat model é o Data Flow Diagram — não um diagrama de arquitetura, não um diagrama de sequência, mas especificamente um DFD que modela como dados fluem entre componentes. DFDs têm quatro elementos:
- Processos — transformam dados (representados por círculos ou retângulos com cantos arredondados). Em um sistema web: o servidor de aplicação, o serviço de autenticação, um worker de background.
- Armazenamentos de dados — onde dados persistem (representados por dois traços paralelos). Bancos de dados, arquivos, caches, filas.
- Atores externos — entidades fora do sistema que interagem com ele (representados por retângulos). Usuários humanos, sistemas parceiros, APIs externas.
- Fluxos de dados — como dados se movem entre os elementos acima (representados por setas com rótulos). Inclui protocolo, autenticação, e natureza do dado.
O elemento que a maioria ignora e que torna o DFD útil para segurança é a trust boundary — uma linha tracejada que separa zonas de confiança diferentes. Tudo que atravessa uma trust boundary é candidato a verificação. A lógica é simples: dentro de uma zona de confiança, você pode assumir que os dados e os chamadores são quem dizem ser; ao cruzar a fronteira, essa suposição cai.
Trust boundaries não são linhas de rede — são fronteiras de suposições. O processo A confia implicitamente nos dados que chegam do processo B? Isso é uma trust boundary independente de onde A e B estão hospedados. Microserviços no mesmo cluster K8s ainda têm trust boundaries entre si se um pode receber dados de fora sem validação.
STRIDE — categorias de ameaça por mnemônico
STRIDE foi desenvolvido por Loren Kohnfelder e Praerit Garg na Microsoft em 1999 como forma de enumerar categorias de ameaça de forma completa e memorizável. Cada letra representa uma categoria:
- S — Spoofing: fingir ser outra entidade. Exemplos: forjar identidade de usuário, fazer uma requisição parecer vir de um serviço interno.
- T — Tampering: modificar dados sem autorização. Exemplos: alterar dados em trânsito, modificar registros no banco, adulterar logs.
- R — Repudiation: negar ter realizado uma ação quando não há evidência suficiente para contradizer. Exemplos: usuário nega ter feito uma transação, processo nega ter recebido uma mensagem.
- I — Information Disclosure: expor informação a quem não deveria ter acesso. Exemplos: mensagem de erro com stack trace, endpoint que retorna dados de outro usuário, log com senha em plaintext.
- D — Denial of Service: tornar o sistema indisponível para usuários legítimos. Exemplos: flood de requisições, consumo de todos os recursos de conexão, queries que bloqueiam o banco.
- E — Elevation of Privilege: obter permissões além das que foram concedidas. Exemplos: SQL injection que acessa dados de outros usuários, path traversal que lê arquivos fora do diretório permitido, JWT com claims forjadas.
O poder do STRIDE não está na criatividade das categorias — está no mapeamento sistemático entre categorias e elementos do DFD. Cada tipo de elemento tem um conjunto de ameaças STRIDE aplicáveis:
- Processos: vulneráveis a todas as seis categorias. São o centro de computação e o alvo mais rico.
- Armazenamentos de dados: principalmente T (tampering nos dados), I (disclosure dos dados armazenados), D (indisponibilidade por corrupção ou lock). Spoofing e Elevation são menos diretos mas relevantes para controle de acesso ao storage.
- Atores externos: principalmente S (spoofing de identidade) e R (repúdio de ações). Um ator externo que finge ser outro é um threat de spoofing; um ator que nega ter feito uma requisição é repúdio.
- Fluxos de dados: principalmente T (tampering em dados em trânsito), I (disclosure de dados interceptados), D (interrupção do fluxo). MITM (man-in-the-middle) ataca exatamente os fluxos de dados.
Aplicar STRIDE apenas ao sistema todo em vez de elemento por elemento resulta em uma lista de ameaças genéricas que não guia implementação. "O sistema pode sofrer spoofing" é inútil. "O fluxo de dados entre o cliente mobile e o endpoint /api/orders pode sofrer spoofing porque não valida o certificado do servidor em builds de debug" é acionável. Granularidade por elemento é o que torna o STRIDE prático.
Aplicando STRIDE na prática — um exemplo concreto
Considere um sistema simples de gerenciamento de documentos: um cliente web, um servidor de API, um banco de dados PostgreSQL, um serviço de autenticação (Keycloak), e um bucket S3 para arquivos. O DFD teria cinco processos/armazenamentos, dois atores externos (usuário e o administrador de sistema), e múltiplos fluxos. As trust boundaries mais óbvias: entre o cliente e o servidor de API (internet, sem confiança), entre o servidor de API e o banco (rede interna, confiança parcial), entre o servidor e o Keycloak (confiança por TLS mútuo).
Aplicando STRIDE ao fluxo "cliente → POST /api/documents":
- S: o servidor valida o JWT corretamente? Verifica algoritmo, iss, aud, exp? Um token forjado ou roubado pode impersonar um usuário legítimo.
- T: o payload do documento é validado antes de persistir? Um campo
userIdno body pode ser sobrescrito pelo cliente para criar documento associado a outro usuário (mass assignment)? - R: existe audit log registrando quem criou qual documento, quando, de qual IP? Sem isso, um usuário pode negar a criação.
- I: a resposta retorna campos sensíveis desnecessários? Um campo
internal_idpode revelar informação sobre volume de dados ou usuários. - D: há rate limiting no endpoint? Um bot pode criar milhares de documentos por segundo, saturando o banco.
- E: o endpoint verifica que o usuário autenticado tem permissão para criar documentos naquele espaço de trabalho? Authorization é diferente de autenticação.
Esse exercício para apenas um endpoint já produz seis linhas de ameaças acionáveis. Um sistema com 30 endpoints e 5 serviços produz centenas — o que torna a documentação estruturada essencial.
Documentando ameaças — o formato que funciona
A forma mais prática de documentar ameaças é uma tabela com campos mínimos mas suficientes para guiar priorização e implementação:
| ID | Elemento | Categoria | Ameaça | Impacto | Probabilidade | Controle | Status |
|-----|-------------------|-----------|---------------------------------------------|----------|---------------|-----------------------------------------|----------|
| T01 | Fluxo: cliente→API| S | JWT forjado ou expirado aceito pelo servidor | Alto | Média | Validar alg, iss, aud, exp no middleware| Mitigado |
| T02 | Processo: API | T | Mass assignment via campo userId no body | Alto | Alta | Usar DTOs sem userId; server side only | Mitigado |
| T03 | Storage: Postgres | I | Query retorna documentos de outros usuários | Crítico | Alta | WHERE user_id = :authenticated_user_id | Mitigado |
| T04 | Fluxo: API→S3 | I | URL pré-assinada compartilhável por horas | Médio | Baixa | TTL de 15 min nas presigned URLs | Aceito |
| T05 | Processo: API | D | POST /documents sem rate limit | Médio | Média | 10 req/min por IP no endpoint | Pendente |
Os campos Impacto e Probabilidade permitem calcular risco e priorizar. Ameaças de impacto alto e probabilidade alta são os quick wins: simples de mitigar e críticas de não ter. O campo Status transforma o documento em um tracker vivo — "Mitigado" com referência ao commit ou PR que implementou o controle, "Aceito" com justificativa explícita e assinatura do responsável, "Pendente" com dono e prazo.
"Aceito" é uma decisão legítima em threat modeling — não toda ameaça precisa de controle. O que não é legítimo é "Aceito" sem registro explícito de quem aceitou, por que, e sob que condições o risco residual voltaria a ser reavaliado. Risco aceito implicitamente não é risco gerenciado.
Árvores de ataque — quando STRIDE não é granular o suficiente
Para ameaças específicas de alto risco, árvores de ataque (attack trees) oferecem uma análise mais profunda. Introduzidas por Bruce Schneier em seu article seminal de 1999 "Attack Trees" na Dr. Dobb's Journal, as árvores modelam os caminhos que um adversário poderia percorrer para atingir um objetivo.
A raiz da árvore é o objetivo do adversário ("obter acesso aos documentos de um usuário premium sem pagar"). Os nós filhos são as subgoals ou ações que levam ao objetivo, conectadas por operadores AND (todos os filhos precisam ser cumpridos) ou OR (qualquer filho é suficiente). Folhas são ataques atômicos.
Objetivo raiz: Acessar documentos de usuário premium sem autorização
│
├── OR: Comprometer credenciais do usuário
│ ├── AND: Phishing com credenciais válidas
│ │ ├── Email convincente enviado (custo baixo)
│ │ └── Usuário clica e submete credenciais (probabilidade média)
│ ├── Credential stuffing com senhas vazadas (custo baixo, automatizável)
│ └── Brute force da senha (custo médio, detectável)
│
├── OR: Explorar falha de autorização na API
│ ├── IDOR: trocar {documentId} por ID de outro usuário (custo baixo)
│ └── JWT com userId modificado e assinatura fraca (custo médio)
│
└── OR: Comprometer o servidor ou banco diretamente
├── SQL injection no endpoint de busca (custo médio)
└── SSRF para acessar metadados da instância AWS (custo médio)
Ao anotar cada nó com custo, probabilidade e detectabilidade do ataque, a árvore revela não apenas o que é possível, mas por onde um atacante racional começaria. Atacantes com tempo e habilidade vão pelo caminho de menor custo e maior probabilidade de sucesso — frequentemente credential stuffing e IDOR antes de tentar SQL injection sofisticado.
Threat modeling no ciclo de desenvolvimento — quando e quem
A pergunta mais comum é: quando fazer threat modeling? A resposta de Shostack é "no design, e depois sempre que o design mudar". O momento ideal é durante o design review, antes de qualquer código: o DFD é desenhado junto com a arquitetura, as ameaças são identificadas sobre o diagrama, e os controles viram requisitos de implementação — não correções pós-facto.
O segundo momento obrigatório é quando o sistema muda de forma significativa: novo endpoint, nova dependência externa, nova forma de armazenar dados sensíveis, novo ator externo com acesso ao sistema. Cada mudança que altera o DFD requer reavaliação das trust boundaries e ameaças afetadas. Não é necessário refazer o threat model inteiro — apenas as seções afetadas pela mudança.
Quanto a quem faz: o autor do sistema (ou do PR de mudança) é o responsável primário por identificar ameaças. Engenheiro de segurança ou AppSec pode revisar e complementar, mas não substituir. Quando o desenvolvedor que escreveu o código é também quem faz o threat model, o feedback loop é direto: identificou uma vulnerabilidade na fase de design, corrige no design. Um processo onde só AppSec faz threat modeling produz um gargalo e documentos que o time de desenvolvimento não lê.
Threat modeling "de checkbox" — feito porque o processo obriga, sem genuína análise de ameaças — é pior que não fazer. Cria uma falsa sensação de cobertura, ocupa tempo em burocracia sem valor, e frequentemente resulta em documentos desatualizados que ninguém lê. O sinal de que o processo está funcionando: o threat model influencia decisões de design. O sinal de que não está: o documento está pronto mas o código ficou igual.
Ferramentas e formatos práticos
Para DFDs, as ferramentas mais usadas em ambientes de engenharia são:
- OWASP Threat Dragon — ferramenta open source, roda no browser ou como app desktop, exporta para JSON e PNG. Integra com GitHub para PR reviews. Suporta STRIDE nativo com anotações por elemento.
- Microsoft Threat Modeling Tool — a ferramenta original da Microsoft, gratuita, Windows-only. Boa para times que já trabalham no ecossistema Microsoft com Azure.
- draw.io / Lucidchart — genérico mas funciona bem com templates de DFD. Mais flexível, menos estruturado para threat analysis.
- Diagrama como código — times que preferem artefatos revisáveis em git usam Mermaid ou PlantUML para DFDs simples, com as ameaças em uma tabela Markdown adjacente. Tem o benefício de ser diff-ável e colocado no repositório junto ao código.
Para equipes que trabalham com código, a abordagem mais durável é threat modeling como texto no repositório — um arquivo threat-model.md com o DFD em Mermaid, a lista de trust boundaries em prosa, e a tabela de ameaças em Markdown. Fica junto com o ADR da feature, é atualizado no mesmo PR que muda a arquitetura, e pode ser revisado como código.
## DFD — Sistema de Documentos (simplificado)
```mermaid
graph TD
U[Usuário / Browser] -->|HTTPS, JWT| API[API Server]
API -->|TCP, mTLS| DB[(PostgreSQL)]
API -->|HTTPS, IAM Role| S3[(S3 Bucket)]
API -->|HTTPS| KC[Keycloak]
A[Admin] -->|HTTPS, RBAC| API
style U fill:#44475a,stroke:#6272a4
style A fill:#44475a,stroke:#6272a4
style KC fill:#282a36,stroke:#ff79c6
```
### Trust Boundaries
1. **Internet → API**: toda requisição do browser é não confiável por definição.
JWT validado no middleware antes de qualquer handler. TLS obrigatório (HSTS).
2. **API → Keycloak**: confiança estabelecida por TLS + client_secret no fluxo
client_credentials. Não confiar em claims do JWT sem validar assinatura contra JWKS.
3. **API → PostgreSQL**: confiança de rede por VPC; ainda assim, queries
parameterizadas — banco não confia em dados vindos da aplicação como SQL.
STRIDE por LINDDUN — quando privacidade é o contexto
STRIDE cobre ameaças de segurança — confidencialidade, integridade, disponibilidade e controle de acesso. Para sistemas que processam dados pessoais em escala, existe um framework complementar chamado LINDDUN (Linkability, Identifiability, Non-repudiation, Detectability, Disclosure of information, Unawareness, Non-compliance), desenvolvido na KU Leuven. LINDDUN aplica a mesma lógica de enumeração sistemática mas para ameaças de privacidade: um dado que pode ser linkado a outro dado revelando identidade, um processamento de dado que o usuário não tem ciência, um dado retido além do necessário.
Para sistemas sob LGPD ou GDPR, o LINDDUN é tão relevante quanto o STRIDE. A pergunta "esse fluxo de dados respeita os princípios de minimização de dados?" é um threat model de privacidade, não de segurança — e os dois não se sobrepõem completamente. Um sistema pode ser seguro (nenhum vazamento não autorizado) e ainda assim não conformante com LGPD (retendo dados além do período autorizado, sem base legal definida).
Métricas de maturidade — o que "bom threat modeling" parece
Times que fazem threat modeling com maturidade apresentam padrões identificáveis. Primeiro: o DFD está no repositório junto com o código, não em um documento Word na pasta do time de segurança. Segundo: o threat model foi atualizado no último trimestre — não é o mesmo documento criado quando o sistema foi projetado há três anos com arquitetura completamente diferente. Terceiro: existem testes de segurança automatizados que cobrem pelo menos as ameaças de probabilidade alta e impacto alto identificadas no threat model. Quarto: quando alguém pergunta "como você protege o endpoint X contra IDOR?", o desenvolvedor responde referenciando o threat model e a linha de código que implementa o controle — não de memória, mas porque o processo é rastreável.
O nível de maturidade mais alto — que poucos times atingem — é threat modeling integrado ao ciclo de PR: qualquer PR que adiciona novo endpoint, nova dependência externa, ou nova forma de armazenar dados sensíveis é bloqueado por uma checklist que obriga a atualizar o threat model. GitHub Actions pode verificar que o arquivo threat-model.md foi modificado quando certas condições são detectadas no diff. Automação não substitui o raciocínio, mas impede que a prática se perca sob pressão de prazo.
Um threat model que não foi consultado nos últimos 90 dias e não reflete mudanças recentes na arquitetura não é um ativo de segurança — é documentação histórica. Manter o threat model vivo tem custo, mas é menor que o custo de descobrir em produção o que estava no diagrama e ninguém atualizou.
Decisões de Engenharia
STRIDE vs PASTA vs LINDDUN — qual framework usar?
STRIDE é o ponto de partida para a maioria dos sistemas — estruturado, memorizável, bem documentado, e adequado para identificar ameaças de segurança em sistemas web e de microsserviços. PASTA (Process for Attack Simulation and Threat Analysis) é mais adequado quando você precisa quantificar risco em termos de negócio e comunicar com stakeholders não técnicos — é mais trabalhoso. LINDDUN é o complemento necessário quando o sistema processa dados pessoais sob LGPD ou GDPR — foca em ameaças de privacidade que STRIDE não cobre. Comece com STRIDE; adicione LINDDUN se você tem dados pessoais em escala.
Qual nível de granularidade para o DFD?
DFD muito granular (um processo por função de código) gera ruído sem valor. DFD muito alto nível (um único bloco "backend") perde as trust boundaries relevantes. O nível certo é: um processo por serviço ou por componente com responsabilidade distinta, um armazenamento por tecnologia de persistência, e um fluxo por protocolo distinto. Para um sistema com 10 microserviços: um DFD de sistema (todos os serviços como blocos) + DFDs de subconjunto para os fluxos de mais alto risco (ex: autenticação, pagamento).
Quem conduz o threat model — dev ou AppSec?
Developer-led é o modelo mais escalável: o desenvolvedor que criou o design faz o threat model, AppSec revisa e complementa. O oposto (AppSec conduz, devs participam) cria gargalo e documentos que o time não sente ownership. O modelo colaborativo funciona melhor: dev escreve o DFD e uma primeira passagem de ameaças; AppSec facilita uma sessão de 60-90 minutos para identificar ameaças que o dev não considerou. O resultado pertence ao dev — o AppSec é o sparring partner, não o autor.
Threat model em arquivo no repo vs ferramenta dedicada?
Arquivo threat-model.md no repositório: vive junto com o código, é diff-ável, pode ser revisado em PR, e não requer ferramenta externa. Desvantagem: DFDs em Mermaid/PlantUML têm limitações de expressividade. Ferramentas (OWASP Threat Dragon, Microsoft TMT): mais ricas graficamente, STRIDE integrado por elemento. Desvantagem: arquivo binário ou JSON que não é legível no diff de PR, e cria dependência de ferramenta. Para times de engenharia: threat-model.md com DFD em Mermaid é a escolha mais durável — o artefato sobrevive às ferramentas.
Perguntas de Entrevista
O que é threat modeling e qual a diferença entre threat modeling e um pentest?
Threat modeling é um processo estruturado de identificar ameaças a um sistema antes do código ser escrito (ou quando o design muda), avaliando probabilidade e impacto, e definindo controles. É uma atividade de design, não de auditoria — o objetivo é influenciar decisões arquiteturais antes que sejam caras de mudar.
Pentest (penetration test) é um exercício de segurança ofensiva: um time tenta comprometer o sistema já construído, usando técnicas reais de ataque, para descobrir vulnerabilidades exploráveis. É uma atividade de validação pós-facto — verifica o que ficou para trás após o desenvolvimento.
Os dois são complementares, não substitutos. Threat modeling encontra ameaças em design antes do código existir (custo de correção: horas). Pentest encontra vulnerabilidades reais no sistema construído (custo de correção: semanas ou mais). Um sistema que passou em pentest sem ter feito threat modeling pode ter design inseguro que o pentest não cobriu. Um sistema com threat modeling excelente mas sem pentest pode ter erros de implementação que o threat model não detectaria.
Aplique STRIDE ao endpoint POST /api/payments em um e-commerce. O que você identificaria?
S (Spoofing): o servidor valida o JWT corretamente — alg, iss, aud, exp? Um token forjado ou roubado pode impersonar outro usuário. O endpoint verifica que o usuário autenticado é o dono do cart_id no payload?
T (Tampering): o valor do pagamento é recalculado server-side ou confiado no body do cliente? Um cliente que envia amount: 0.01 para um produto de R$1000 está tamperando. O order_id no payload pode ser de outro usuário?
R (Repudiation): existe audit log com user_id, timestamp, valor, IP, e transaction_id para cada tentativa — bem-sucedida ou não? Sem isso, um usuário pode negar a transação.
I (Information Disclosure): a resposta de erro expõe stack trace, detalhes de banco, ou IDs internos? Uma resposta 500 com PSQLException: duplicate key in payments table revela schema interno.
D (Denial of Service): há rate limiting por user_id e por IP? Um atacante pode tentar milhares de combinações de cartão até encontrar uma válida — e cada tentativa custaria ao processador.
E (Elevation of Privilege): o endpoint verifica que o usuário tem permissão para fazer pagamento (ex: conta não suspensa)? A autorização verifica o espaço de trabalho, não apenas a autenticação?
O que é uma trust boundary? Como você a identificaria em uma arquitetura de microsserviços?
Uma trust boundary é uma linha que separa zonas de confiança diferentes em um DFD — tudo que a atravessa é candidato a verificação. A lógica: dentro de uma zona de confiança, você assume que dados e chamadores são quem dizem ser; ao cruzar a fronteira, essa suposição cai e você precisa de validação explícita.
Trust boundaries não são necessariamente fronteiras de rede. Em uma arquitetura de microsserviços, as fronteiras mais relevantes são: (1) Internet → API Gateway: toda requisição vinda do cliente é não confiável por definição — JWT validado, rate limiting, WAF; (2) Serviço A → Serviço B: mesmo que estejam no mesmo cluster K8s, se o serviço B recebe dados que poderiam ter sido manipulados pelo cliente antes de chegar ao serviço A, há uma trust boundary; (3) Aplicação → Banco de dados: o banco não confia nos dados que chegam como SQL — queries parametrizadas; (4) Sistema interno → API de terceiro: a API externa é um ator externo não controlado.
A pergunta prática para identificar trust boundaries: "Esse componente pode receber dados de alguém que não controlo?" Se sim, há uma trust boundary. Um serviço interno que só recebe dados de outros serviços internos com mTLS pode ter uma boundary menor que um serviço que processa webhooks de terceiros.
Como você decide entre "Aceito" e "Mitigado" para uma ameaça identificada? Quem tem autoridade para aceitar?
A decisão entre aceitar e mitigar começa com uma avaliação de risco: Impacto × Probabilidade. Ameaças de impacto crítico raramente devem ser aceitas — o custo de um incidente supera qualquer custo de mitigação. Ameaças de impacto baixo e probabilidade baixa podem ser aceitas se o custo de mitigação for desproporcionalmente alto.
"Aceito" é uma decisão legítima — não toda ameaça precisa de controle. O que não é legítimo é "Aceito" implícito (a ameaça existe mas ninguém decidiu conscientemente). "Aceito" no threat model requer: (1) registro explícito de quem aceitou (nome, cargo); (2) justificativa documentada (ex: "probabilidade muito baixa dado que o endpoint é interno e acessado apenas por serviços com mTLS"); (3) condições de reavaliar (ex: "reavaliar se o endpoint se tornar público"); (4) data de revisão.
Quem tem autoridade para aceitar depende do impacto: ameaças de impacto médio → tech lead ou engenheiro sênior responsável pelo sistema; ameaças de impacto alto → product owner + tech lead, documentado; ameaças de impacto crítico → decisão escalonada para direção de engenharia ou segurança. "Aceito por pressão de prazo sem análise" é risco implícito — o pior dos casos.
Como você introduziria threat modeling em um time que nunca fez antes e está sob pressão de prazo?
A abordagem que gera menor resistência e maior adoção é começar pequeno e mostrar valor rápido, sem criar processo pesado. Sequência recomendada:
Semana 1 — piloto de 90 minutos: escolha uma feature nova que está em design, reúna o time de desenvolvimento, e conduza uma sessão de "o que pode dar errado?" usando o DFD da feature. Não use terminologia de segurança no início — use "como alguém poderia abusar disso?". Documente as ameaças encontradas em uma tabela simples. Mostre quantas o time não havia considerado — o efeito surpresa gera interesse.
Semana 2-4 — template leve: crie um arquivo threat-model.md mínimo para a feature do piloto. Mostre que é revisável em PR, que cabe em uma página, e que resolve "quem aceitou esse risco?". Não force STRIDE completo no começo — "S/T/R/I/D/E por elemento" pode vir depois.
Mês 2+ — checklist em PRs: adicione uma pergunta na template de PR: "Este PR adiciona novo endpoint, armazenamento de dado sensível, ou integração externa? Se sim, o threat-model.md foi atualizado?" Não bloquear automaticamente no início — apenas criar consciência. A automação vem quando o time já vê valor e não precisa ser forçado.
O que evitar: uma sessão de 4 horas com todo o time no primeiro dia, STRIDE completo em todos os serviços antes de mostrar qualquer valor, ou criar um processo que requer ferramenta de terceiro que ninguém tem acesso. Fricção alta no início mata a adoção antes de começar.
Como praticar
-
Threat model de um sistema que você já conhece. Escolha um sistema em produção no seu trabalho (ou um projeto pessoal). Desenhe o DFD com no mínimo 4 elementos e identifique 2 trust boundaries. Aplique STRIDE por elemento e preencha a tabela de ameaças com pelo menos 6 ameaças.
Critério: A tabela tem pelo menos 3 ameaças de probabilidade Alta ou Crítica; pelo menos 1 ameaça está classificada como "Aceito" com justificativa documentada; o DFD identifica claramente onde estão as trust boundaries. -
Revisar um PR com olhos de threat modeling. Na próxima vez que você revisar um PR que adiciona um endpoint novo, uma nova integração externa, ou armazenamento de dado sensível, faça as perguntas STRIDE explicitamente nos comentários. Não como processo burocrático, mas como parte genuína da revisão.
Critério: Pelo menos 2 perguntas STRIDE explícitas nos comentários do PR; pelo menos 1 pergunta revela uma suposição não documentada sobre confiança entre componentes; o autor do PR consegue responder ou adiciona mitigação ao código. -
Construir o template no repositório. Crie um arquivo
docs/threat-model.mdem um projeto existente com a estrutura mínima: DFD em Mermaid, lista de trust boundaries em prosa, e tabela de ameaças com pelo menos 5 ameaças identificadas.
Critério: O arquivo renderiza corretamente no GitHub; o DFD em Mermaid mostra pelo menos 4 elementos e 1 trust boundary visível; a tabela tem os campos ID, Elemento, Categoria, Ameaça, Impacto, Probabilidade, Controle, Status. -
Construir uma árvore de ataque para um sistema que você conhece. Escolha o objetivo de ataque mais crítico para o seu sistema (ex: "acessar dados de outro usuário", "fazer uma transação sem autorização"). Construa uma árvore de ataque com pelo menos 3 caminhos distintos, anotando custo e detectabilidade para cada nó folha.
Critério: A árvore tem operadores AND e OR em pelo menos 1 nó; o caminho de menor custo para o atacante está identificado; um controle específico para o caminho de menor custo está proposto e o custo do controle é comparado com o risco residual sem ele. -
Automatizar a verificação de threat model em PRs. Escreva um GitHub Actions workflow que verifica se o arquivo
docs/threat-model.mdfoi modificado quando um PR adiciona novos arquivos em caminhos de controllers ou handlers (ex:src/controllers/**ou**/handlers/**). O workflow deve emitir um aviso (não falhar o build) se a condição for verdadeira e o threat model não foi atualizado.
Critério: O workflow detecta corretamente PRs que adicionam controllers sem atualizar o threat model; o aviso é claro sobre o que precisa ser feito; o workflow não falha em PRs que não adicionam novos handlers.
Referências para aprofundar
- book Threat Modeling: Designing for Security — Adam Shostack (Wiley, 2014).
- book The Web Application Hacker's Handbook — Stuttard e Pinto (Wiley, 2011).
- book Secure by Design — Johnsson, Deogun e Sawano (Manning, 2019).
- article Attack Trees — Bruce Schneier (Dr. Dobb's Journal, 1999).
- article Threat Modeling Manifesto — Alyssa Miller et al. (2020).
- docs OWASP Threat Dragon — Documentação Oficial — OWASP Foundation.
- docs Microsoft SDL Threat Modeling Tool — Guia — Microsoft.
- article LINDDUN Privacy Threat Modeling — KU Leuven (linddun.org, atualizado 2022).
- video Threat Modeling in 2019 — Adam Shostack (RSA Conference, 2019).
- paper STRIDE Chart — Threats per DFD Element — Microsoft (publicado como parte do SDL).
- article Threat Modeling for Agile Teams — OWASP (OWASP Cheat Sheet Series).
- book Building Secure and Reliable Systems — Google SRE (O'Reilly, 2020).