---
id: owasp-top10-threat-assessment
domain: security
agents: [qa]
when: "ao fazer uma avaliação de risco de segurança de uma aplicação"
---

# OWASP Top 10 (2021) — threat assessment acionável

Fonte: OWASP Top 10:2021 (owasp.org/Top10). Cada categoria abaixo traz o **risco em uma linha**,
**como detectar** (e onde no pipeline), um **cenário de ataque concreto** e a **prevenção** — extraídos
do material oficial, não inventados.

## O problema

Uma avaliação de risco genérica produz um relatório que ninguém usa: "valide entradas", "use HTTPS",
"mantenha dependências atualizadas". Isso é prosa. Um threat assessment **útil** amarra cada risco a:

1. **Um CWE** concreto (rastreável, não opinião).
2. **Uma técnica de detecção** com a ferramenta certa (SAST/DAST/IAST/SCA) e o **ponto do pipeline**
   onde ela roda — porque SAST acha SQLi mas não acha broken access control; DAST acha o oposto.
3. **Um cenário de ataque** que o time consegue reproduzir.
4. **Um controle de prevenção** verificável por teste.

Os tells de um assessment ruim: lista as 10 categorias sem dizer **como achar cada uma**; mistura
SAST e DAST como se fossem intercambiáveis; recomenda "input validation" para A01 (Broken Access
Control), onde validação de input não resolve nada — o problema é autorização, não sanitização.

### A regra que mais se erra: qual ferramenta acha o quê

| Técnica | Quando roda | Acha bem | NÃO acha |
|---|---|---|---|
| **SAST** (estático, lê código) | Pre-commit / PR / CI build | A03 Injection, A02 cripto fraca, hardcoded secrets, A08 deserialização | A01 access control (precisa de contexto de runtime/autorização), A05 config de ambiente, A09 logging gaps |
| **DAST** (dinâmico, ataca app rodando) | Staging / nightly / pre-release | A01 (force browsing, IDOR), A05 (headers, error pages), A10 SSRF, A07 (sem rate-limit em login) | Bugs em caminhos não exercitados; lógica de negócio (A04) sem casos de abuso modelados |
| **IAST** (instrumenta app durante testes) | Durante testes E2E/integração em CI | A03 com baixo falso-positivo (vê o dado fluir até o sink), A02 em runtime | Cobertura limitada ao que os testes exercitam |
| **SCA** (software composition analysis) | Pre-commit / CI / monitoramento contínuo | A06 componentes vulneráveis (CVE/NVD), A08 supply chain | Vulnerabilidades no SEU código |
| **Threat modeling** (manual, design-time) | Antes de codar; em mudança de fluxo crítico | A04 Insecure Design, A01 a nível de regra de negócio | Bugs de implementação |
| **Secret scanning** | Pre-commit (hook) + CI | A02 (CWE-259 hardcoded), A07 default creds | — |

Regra prática: **SAST + SCA + secret scanning no PR (rápido), DAST + IAST em staging (lento), threat
modeling no design.** Nenhuma das três sozinha cobre o Top 10.

## O conhecimento / os princípios

### A01:2021 — Broken Access Control

- **Risco (1 linha):** usuário age fora das permissões pretendidas → leitura/escrita/destruição de
  dados de outros ou execução de função de negócio fora do seu limite. (CWE-200, CWE-201, CWE-352)
- **Como detectar:** **DAST** + teste manual de autorização em staging (SAST é cego aqui). Force
  browsing a páginas privilegiadas; trocar IDs em IDOR; chamar API com método não autorizado
  (POST/PUT/DELETE). Em CI, **testes de integração de autorização** rodando como user A tentando
  acessar recurso de user B.
- **Cenário de ataque (oficial):** atacante troca o parâmetro do browser para acessar conta alheia —
  `https://example.com/app/accountInfo?acct=notmyacct` — ou faz force browsing a
  `https://example.com/app/admin_getappInfo` sem ser admin.
- **Prevenção:** *deny by default* para todo recurso não-público; impor **ownership de registro** (não
  assumir que o user pode acessar qualquer registro); um único mecanismo de access control reusado em
  todo o app; invalidar sessão server-side no logout; **testes unit e de integração de access control**;
  rate-limit; logar falhas de access control e alertar.

```sql
-- VULNERÁVEL: confia no acct vindo do cliente, sem checar ownership
SELECT * FROM accounts WHERE acct_id = :acct;        -- :acct = "notmyacct"

-- CORRETO: ownership forçado no WHERE — o user só vê o que é dele
SELECT * FROM accounts WHERE acct_id = :acct AND owner_user_id = :session_user_id;
```

### A02:2021 — Cryptographic Failures

- **Risco (1 linha):** falha (ou ausência) de criptografia expõe dado sensível. (CWE-259 senha
  hardcoded, CWE-327 algoritmo quebrado/arriscado, CWE-331 entropia insuficiente)
- **Como detectar:** **SAST** para MD5/SHA1/algoritmos depreciados e padding PKCS#1 v1.5; **secret
  scanning** no pre-commit para chaves/senhas hardcoded; **DAST**/análise de TLS em staging para falta
  de HSTS, downgrade HTTP, ciphers fracos.
- **Cenário de ataque (oficial):** app armazena cartão com criptografia automática do banco, que
  **descriptografa ao ler** — uma falha de SQL injection retorna os números em texto claro. Outro:
  banco de senhas usa hash **sem salt ou hash simples**; um upload flaw permite roubar o arquivo.
- **Prevenção:** classificar o dado; **não armazenar dado sensível desnecessário**; criptografar em
  repouso e em trânsito (TLS com FS, HSTS); **senhas com Argon2/scrypt/bcrypt/PBKDF2** com work factor;
  IV via CSPRNG e **nunca reutilizado com a mesma chave**; usar **authenticated encryption**; evitar
  MD5, SHA1, PKCS#1 v1.5.

```python
# VULNERÁVEL — CWE-327 / CWE-916: hash rápido e sem salt
import hashlib
pwd_hash = hashlib.sha256(password.encode()).hexdigest()

# CORRETO — adaptive + salted com work factor (Argon2)
from argon2 import PasswordHasher
ph = PasswordHasher()                # gera salt e parametriza custo
pwd_hash = ph.hash(password)
ph.verify(pwd_hash, password)
```

### A03:2021 — Injection

- **Risco (1 linha):** dado não-confiável não validado/sanitizado vira parte de query ou comando.
  (CWE-89 SQLi, CWE-79 XSS, CWE-73 path)
- **Como detectar:** **SAST** (taint analysis: source → sink) no PR; **IAST** durante testes E2E para
  baixo falso-positivo; **DAST** em staging para XSS refletido e SQLi cego.
- **Cenário de ataque (oficial):** construção de SQL por concatenação em Java —
  `String query = "SELECT * FROM accounts WHERE custID='" + request.getParameter("id") + "'";` — e o
  atacante envia `id` = `' UNION SELECT SLEEP(10);--`, via
  `http://example.com/app/accountView?id=' UNION SELECT SLEEP(10);--`, mudando o sentido da query.
- **Prevenção:** **API segura/parametrizada ou ORM** (evita o interpretador); validação positiva
  server-side (não é defesa completa); para query dinâmica residual, **escape com a sintaxe específica
  do interpretador**.

```java
// VULNERÁVEL (oficial) — concatenação
String query = "SELECT * FROM accounts WHERE custID='" + request.getParameter("id") + "'";

// CORRETO — query parametrizada (PreparedStatement)
PreparedStatement ps = conn.prepareStatement(
    "SELECT * FROM accounts WHERE custID = ?");
ps.setString(1, request.getParameter("id"));   // o input nunca vira código SQL
ResultSet rs = ps.executeQuery();
```

### A04:2021 — Insecure Design

- **Risco (1 linha):** controle ausente ou ineficaz **por design** (falha de arquitetura, não de
  implementação). (CWE-209 erro com info sensível, CWE-256/522 credenciais, CWE-501 trust boundary)
- **Como detectar:** **threat modeling no design** (SAST/DAST não acham — não há bug, há ausência de
  controle); revisão de arquitetura; **casos de abuso** escritos como testes de integração.
- **Cenário de ataque (oficial):** rede de cinema dá desconto de grupo com máximo de 15 lugares antes
  de exigir depósito; o atacante modela o fluxo e reserva **600 lugares em todos os cinemas** em poucos
  requests, causando perda massiva. Outro: e-commerce sem proteção contra bots de scalpers comprando
  placas de vídeo.
- **Prevenção:** SDLC seguro com AppSec; **biblioteca de design patterns seguros**; threat modeling
  para auth/access control/lógica de negócio; **plausibility checks em cada camada**; unit/integration
  tests que validam os fluxos críticos contra o threat model (use-cases **e** misuse-cases); limitar
  consumo de recurso por usuário/serviço.

### A05:2021 — Security Misconfiguration

- **Risco (1 linha):** hardening ausente, features desnecessárias ligadas, credenciais default,
  erros vazando info. (CWE-16 Configuration, CWE-611 XXE, CWE-614 cookie sem Secure)
- **Como detectar:** **DAST** em staging (security headers ausentes, directory listing, stack traces
  em erro, XXE); scanners de config/IaC no CI; checagem de buckets de cloud com permissão default.
- **Cenário de ataque (oficial):** app de exemplo com falha conhecida fica em produção e
  **credencial admin default não foi trocada**; directory listing ligado deixa baixar classes
  compiladas e descompilar; erro detalhado (stack trace) **revela versões de componentes**; storage de
  cloud com sharing default aberto à Internet.
- **Prevenção:** **processo de hardening repetível**; plataforma mínima (sem features/samples
  desnecessários); review de config no patch management; arquitetura segmentada; **security headers**
  enviados ao cliente; **processo automatizado** que verifica a efetividade das configs em todos os
  ambientes.

```http
# CORRETO — diretivas de segurança enviadas ao cliente (mitiga A05/A02)
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Content-Security-Policy: default-src 'self'
X-Content-Type-Options: nosniff
Set-Cookie: session=...; Secure; HttpOnly; SameSite=Strict
```

### A06:2021 — Vulnerable and Outdated Components

- **Risco (1 linha):** uso de componentes com vulnerabilidade conhecida; componentes rodam com o
  mesmo privilégio do app. (CWE-937, CWE-1035, CWE-1104 componente não mantido)
- **Como detectar:** **SCA** no PR e **monitoramento contínuo** (OWASP Dependency-Check, retire.js),
  acompanhando CVE/NVD com assinatura de alertas — não é evento único, é processo de lifetime.
- **Cenário de ataque (oficial):** **CVE-2017-5638**, RCE no Struts 2, permite executar código
  arbitrário no servidor e foi responsabilizado por grandes vazamentos. IoT é caso difícil de patch
  com alto risco (biomédico, crítico).
- **Prevenção:** eliminar dependências/features não usadas; **rastrear versões cliente e servidor**
  continuamente; obter componentes **só de fontes oficiais por links seguros**, preferir **pacotes
  assinados**; virtual patching quando não dá para corrigir; **plano contínuo** de monitorar/triar/
  aplicar updates pela vida da aplicação.

### A07:2021 — Identification and Authentication Failures

- **Risco (1 linha):** confirmação de identidade, autenticação e gestão de sessão fracas abrem
  credential stuffing, brute force e reuso de credencial roubada. (CWE-287, CWE-297, CWE-384 session
  fixation)
- **Como detectar:** **DAST**/teste de auth em staging (login sem rate-limit, mensagens que permitem
  enumeração de conta, timeout de sessão incorreto); **secret scanning** para credenciais default;
  testes que verificam rotação de session ID após login.
- **Cenário de ataque (oficial):** **credential stuffing** — atacante usa listas de senhas conhecidas
  contra um app que funciona como validador de senha sem proteção; reuso de sessão em computador
  público quando o user não faz logout (timeout impróprio).
- **Prevenção:** **MFA** contra stuffing/brute force; **não shipar credenciais default** (sobretudo
  admin); testar senha nova contra a lista das **10.000 piores senhas**; alinhar política ao **NIST
  800-63b**; **mesma mensagem para todos os desfechos** (evita enumeração); atrasar/limitar logins
  falhos; **session manager server-side que gera novo session ID de alta entropia após login**.

### A08:2021 — Software and Data Integrity Failures

- **Risco (1 linha):** código e infra que não protegem contra violação de integridade (updates,
  deserialização, pipeline CI/CD). (CWE-829, CWE-494 download sem checagem, CWE-502 deserialização)
- **Como detectar:** **SCA**/supply-chain tool (OWASP Dependency-Check, CycloneDX) no CI; **SAST**
  para deserialização insegura; revisão de **segregação e access control do pipeline CI/CD**.
- **Cenário de ataque (oficial):** **SolarWinds Orion** — nation-state ataca o mecanismo de update e
  distribui update malicioso a **18.000+ organizações**. **Deserialização insegura**: atacante nota a
  assinatura `rO0` (objeto Java em base64) e usa o **Java Serial Killer** para RCE no servidor.
- **Prevenção:** **assinaturas digitais** para verificar origem e integridade; libs/deps de
  **repositórios confiáveis** (considerar repo interno vetado); supply-chain tool checando CVE; review
  de mudanças de código e config; **CI/CD com segregação e access control**; **não enviar dado
  serializado sem assinatura/integridade** a clientes não-confiáveis.

### A09:2021 — Security Logging and Monitoring Failures

- **Risco (1 linha):** sem logging/monitoramento suficiente, breaches ativos não são detectados,
  escalados nem respondidos. (CWE-117 log injection, CWE-223 omissão, CWE-532 dado sensível em log,
  CWE-778 logging insuficiente)
- **Como detectar:** revisão de cobertura de logs (login/access control/validação falham e são
  logados?); teste se **transações de alto valor** têm trilha íntegra (append-only); verificar tempo
  de detecção em exercício de resposta a incidente.
- **Cenário de ataque (oficial):** provedor de plano de saúde infantil **não detectou** o breach por
  falta de logging/monitoramento; um terceiro avisou que um atacante acessou e modificou registros de
  **3,5 milhões de crianças** — o breach pode ter durado **mais de sete anos** (desde 2013). Companhia
  aérea europeia foi multada em **£20 milhões** após 400.000 registros de pagamento colhidos.
- **Prevenção:** logar login/access control/validação com **contexto de usuário** e retenção para
  forense; logs em **formato consumível** por SIEM; **encodar log** para evitar injeção; trilha de
  auditoria **append-only com controle de integridade** para transações de alto valor; alerting do
  DevSecOps; **plano de resposta a incidente** (NIST 800-61r2).

### A10:2021 — Server-Side Request Forgery (SSRF)

- **Risco (1 linha):** o app busca um recurso remoto **sem validar a URL fornecida pelo usuário**.
  (CWE-918)
- **Como detectar:** **DAST** em staging com payloads SSRF; **SAST** para sinks de fetch HTTP que
  recebem URL de input do usuário; revisar se há **allow-list** de schema/porta/destino.
- **Cenário de ataque (oficial):** **port scanning** da rede interna via timing/respostas; leitura de
  arquivo/serviço local — `file:///etc/passwd` e `http://localhost:28017/`; **metadata de cloud** via
  `http://169.254.169.254/`; abuso de serviço interno para **RCE ou DoS**.
- **Prevenção (rede):** segmentar acesso a recurso remoto; firewall **deny by default** bloqueando
  todo tráfego intranet não-essencial; logar fluxos aceitos/bloqueados. **(app):** validar todo input
  do cliente; impor **schema, porta e destino por allow-list positiva**; **não devolver resposta crua**
  ao cliente; **desabilitar redirects HTTP**; cuidar de **DNS rebinding** e **TOCTOU**.

```python
# VULNERÁVEL — busca a URL que o usuário mandou (acesso a 169.254.169.254, file://, localhost)
url = request.args["url"]
return requests.get(url).text          # devolve resposta crua = SSRF

# CORRETO — allow-list de schema + host; sem redirect; sem devolver resposta crua
from urllib.parse import urlparse
ALLOWED_HOSTS = {"api.parceiro.com"}
p = urlparse(request.args["url"])
if p.scheme != "https" or p.hostname not in ALLOWED_HOSTS:
    abort(400)
r = requests.get(p.geturl(), allow_redirects=False, timeout=5)
return {"ok": r.status_code == 200}    # nunca o corpo cru
```

## Checklist de threat-assessment (acionável por risco)

Marque por categoria; qualquer "não" é um achado a registrar com o CWE correspondente.

- [ ] **A01** Testes de integração provam que user A **não** acessa recurso de user B (IDOR/force
  browsing); APIs têm controle em POST/PUT/DELETE; *deny by default*; ownership no `WHERE`.
- [ ] **A02** SAST não acusa MD5/SHA1/PKCS#1 v1.5; senhas em Argon2/bcrypt/scrypt/PBKDF2 com salt;
  secret scanning verde (nada hardcoded); TLS + HSTS em todas as páginas.
- [ ] **A03** Zero concatenação de input em SQL/HQL/comando — tudo parametrizado/ORM; SAST/IAST verde
  para taint source→sink; DAST não acha XSS/SQLi cego.
- [ ] **A04** Fluxos críticos têm threat model com **misuse-cases** virados em teste; limites de
  negócio (qtd, valor) impostos por domínio; rate/resource limit por usuário.
- [ ] **A05** Hardening repetível + processo automatizado de verificação; sem credencial default; sem
  directory listing; erro **não** vaza stack trace; security headers presentes; buckets fechados.
- [ ] **A06** SCA no PR + monitoramento contínuo de CVE/NVD; sem dependência não-mantida; componentes
  de fonte oficial/assinados; plano de patch de lifetime.
- [ ] **A07** MFA disponível; sem credencial default; rate-limit/atraso em login falho; mensagem
  uniforme (anti-enumeração); novo session ID de alta entropia após login; senha checada vs piores 10k.
- [ ] **A08** Updates/artefatos com assinatura digital; deps de repo confiável + supply-chain tool;
  CI/CD segregado com access control; nada serializado sem integridade enviado a cliente não-confiável.
- [ ] **A09** Login/access control/validação falham **e são logados** com contexto; logs em formato de
  SIEM e encodados; trilha append-only para alto valor; alerting e plano de IR (NIST 800-61r2).
- [ ] **A10** Toda URL de fetch passa por allow-list de schema/porta/host; redirects desabilitados;
  resposta crua nunca devolvida; firewall deny-by-default no egress; proteção a DNS rebinding/TOCTOU.

## Tabela de decisão "use X quando Y"

| Quando (Y) | Use (X) | Por quê |
|---|---|---|
| Achar **A03 Injection / A02 cripto fraca / hardcoded secret** antes do merge | **SAST + secret scanning no PR** | Lê o código sem rodar; pega taint source→sink e algoritmos depreciados rápido |
| Achar **A01 access control / A05 misconfig / A10 SSRF / A07 sem rate-limit** | **DAST em staging** | Só ataque ao app rodando revela autorização, headers, error pages e SSRF reais |
| Reduzir **falso-positivo de injection** com cobertura de teste | **IAST durante E2E em CI** | Instrumenta e vê o dado chegar ao sink — confirma exploitabilidade |
| Achar **A06 componente vulnerável / A08 supply chain** | **SCA no PR + monitoramento contínuo (CVE/NVD)** | Vulnerabilidade está na dependência, não no seu código; é processo de lifetime |
| Achar **A04 Insecure Design** (limite de negócio, fluxo abusável) | **Threat modeling no design + misuse-cases como teste** | Não há bug para scanner achar — é ausência de controle por design |
| Detectar **A09** (breach passando despercebido) | **Revisão de cobertura de log + alerting + exercício de IR** | Nenhum scanner mede "você perceberia um ataque agora?" |
| Decidir **prevenção de A01** | **Ownership no WHERE + deny-by-default**, não input validation | A01 é autorização; sanitizar input não corrige acesso indevido |
| Decidir **prevenção de A03** | **Query parametrizada/ORM**, não só escaping | Escaping é defesa residual; parametrização tira o input do plano de código |
| Decidir **prevenção de A07 contra stuffing** | **MFA + rate-limit + mensagem uniforme** | Senha forte sozinha não para reuso de credencial roubada |
| Priorizar achados | **Por impacto do CWE + exploitabilidade do cenário**, não por categoria | A06 com RCE conhecido (ex. CVE-2017-5638) > A05 cosmético |
