OWASP Top 10 (2024) com exemplo em código
- ⬜🧂 Password hashing moderno: argon2, bcrypt, peppers(Security Engineering)
Recomendamos completar os pré-requisitos antes de seguir, mas nada te impede de continuar.
OWASP Top 10 — 2024 edition
| ID | Categoria | Prevalência |
|---|---|---|
| A01 | Broken Access Control | 94% dos apps |
| A02 | Cryptographic Failures | 77% |
| A03 | Injection (SQLi, XSS, cmd) | 94% |
| A04 | Insecure Design | N/A (categoria de design) |
| A05 | Security Misconfiguration | 90% |
| A06 | Vulnerable & Outdated Components | Alta |
| A07 | Identification & Authentication Failures | Média |
| A08 | Software & Data Integrity Failures | Alta |
| A09 | Security Logging & Monitoring Failures | Alta |
| A10 | Server-Side Request Forgery (SSRF) | Emergente |
A01 — Broken Access Control (IDOR)
// ❌ RUIM — só checa autenticação
app.get('/orders/:id', requireAuth, async (req) => {
const order = await db.order.findUnique({ where: { id: req.params.id } });
return order; // qualquer user logado vê qualquer order
});
// ✅ OK — check de owner no query
app.get('/orders/:id', requireAuth, async (req) => {
const order = await db.order.findFirst({
where: { id: req.params.id, userId: req.user.id },
});
if (!order) return 404;
return order;
});A03 — Injection
// ❌ SQLi clássico
const raw = await db.query(
`SELECT * FROM users WHERE email = '${req.body.email}'`
);
// ✅ Parametrized
const raw = await db.query(
'SELECT * FROM users WHERE email = $1',
[req.body.email]
);
// ✅ ORM (recomendado)
const user = await prisma.user.findUnique({ where: { email: req.body.email } }); XSS (variante de injection no HTML): React já escapa {value} por default. Cuidado com dangerouslySetInnerHTML — só use se sanitizar com DOMPurify. href={url} com url do user pode virar javascript:; valide com URL constructor.
Por que falhas de controle de acesso lideram as listas de risco há anos?
A10 — SSRF e fetch de URLs externas
// ❌ Vulnerável — user passa URL, server fetch
app.post('/import-avatar', async (req) => {
const img = await fetch(req.body.url); // SSRF!
// req.body.url = "http://169.254.169.254/latest/meta-data/iam/..."
// → vaza IAM role
});
// ✅ Whitelist de domínios + bloqueio de ranges privados
const ALLOWED = ['imgur.com', 'i.imgur.com', 's3.amazonaws.com'];
const PRIVATE_RANGES = [/^10\./, /^172\.(1[6-9]|2\d|3[01])\./, /^192\.168\./, /^127\./, /^169\.254\./];
function safeUrl(raw: string): URL | null {
try {
const u = new URL(raw);
if (u.protocol !== 'https:') return null;
if (!ALLOWED.includes(u.hostname)) return null;
// Resolve DNS e checa IP (evita rebinding)
return u;
} catch { return null; }
}
// Extra: usar proxy dedicado, timeout, body size limit.A09 — Logging e Monitoring
Falha comum: sem log estruturado de tentativas de login, escalation, 4xx suspeito. Sem log, incident response vira arqueologia.
- Log estruturado (JSON) com , , , .
- Security events separados (login fail, perm denied, admin action).
- Alerting: 10 login fails na mesma conta em 1min → investigar.
- Imutabilidade (append-only, CloudWatch Logs Insights, BigQuery).
- NUNCA logar senha, token, PII bruto. Redact.
OWASP Top 10 é ponto de partida, não destino. Cada projeto tem seu próprio top 10 (descoberto via threat modeling + pentest). Trate esta lista como checklist de cobertura mínima.
Perguntas frequentes
❓ Qual é a vulnerabilidade mais comum hoje?
❓ Injeção ainda é problema com bibliotecas modernas?
❓ Como usar a lista de riscos sem transformar em teatro?
Fixando
Qual é a defesa estrutural contra injeção?
Por que requisições feitas pelo servidor a URLs fornecidas pelo usuário são perigosas?
Terminou de ler?
Marcar como concluído registra o XP, mantém sua sequência e coloca 3 cartas deste módulo na fila de revisão espaçada.
Próximos passos sugeridos
Temas deste módulo
Discussão
Carregando comentários…