OWASP Top 10 para APIs
Mapeie os riscos do OWASP API Security Top 10 para mitigações concretas em Node.js - validação Zod, autenticação em nível de objeto, limites de taxa e escaneamento de dependências.
Busque em todas as páginas da documentação
Mapeie os riscos do OWASP API Security Top 10 para mitigações concretas em Node.js - validação Zod, autenticação em nível de objeto, limites de taxa e escaneamento de dependências.
Cartão de receita de referência rápida - pronto para copiar e colar.
// Padrão: validar -> autenticar -> autorizar -> handler
app.get("/orders/:id", async (req, res) => {
const user = requireAuth(req);
const orderId = z.string().uuid().parse(req.params.id);
const order = await ordersRepo.findById(orderId);
if (!order || order.tenantId !== user.tenantId) {
return res.status(404).json({ error: "Not found" });
}
res.json(order);
});Quando usar isso:
import express from "express";
import rateLimit from "express-rate-limit";
import { z } from "zod";
import helmet from "helmet";
class HttpError extends Error {
constructor(public status: number, message: string) {
super(message);
}
}
const usersRepo = {
async update(id: string, patch: { name: string }) {
return { id, ...patch };
},
};
const app = express();
app.use(helmet());
app.use(express.json({ limit: "1mb" }));
const authLimiter = rateLimit({ windowMs: 60_000, max: 10 });
app.post("/auth/login", authLimiter, async (req, res) => {
const body = z.object({
email: z.string().email(),
password: z.string().min(8),
}).safeParse(req.body);
if (!body.success) return res.status(400).json({ error: "Invalid input" });
// Comparação em tempo constante em um serviço de autenticação real
res.json({ token: "..." });
});
type User = { id: string; tenantId: string; role: string };
function requireAuth(req: express.Request): User {
const user = (req as express.Request & { user?: User }).user;
if (!user) throw new HttpError(401, "Unauthorized");
return user;
}
app.patch("/users/:id", async (req, res) => {
const actor = requireAuth(req);
const targetId = z.string().uuid().parse(req.params.id);
if (actor.id !== targetId && actor.role !== "admin") {
return res.status(403).json({ error: "Forbidden" });
}
const patch = z.object({ name: z.string().min(1).max(120) }).parse(req.body);
res.json(await usersRepo.update(targetId, patch));
});O que isso demonstra:
tenantId e propriedade no acesso ao objeto (404, não 403, para evitar enumeração).| Risco | Mitigação Node.js |
|---|---|
| API1: BOLA | Verifique resource.ownerId === user.id (ou tenant) em cada rota de ID |
| API2: Autenticação Quebrada | bcrypt/argon2, JWT de curta duração, limite de taxa /login, rotacione segredos |
| API3: Atribuição em Massa | parse Zod com campos permitidos explícitos; nunca espalhe req.body em ORM |
| API4: Consumo de Recursos | Limites de corpo, limites de paginação, limites de taxa, filas de trabalhos pesados |
| API5: BFLA | Verificações de função por endpoint; rotas de administrador atrás de middleware separado |
| API6: Fluxo Irrestrito | Limites de taxa OTP, captcha no cadastro, chaves de idempotência em pagamentos |
| API7: SSRF | Lista de permissão de URL, resolve DNS + bloqueia IPs privados (Guarda-corpos SSRF) |
| API8: Configuração Incorreta | Helmet, desabilita x-powered-by, sem credenciais padrão, npm audit em CI |
| API9: Inventário | Especificação OpenAPI, lint de rotas, desativa endpoints não utilizados |
| API10: Consumo Inseguro | Valide payloads de webhook de terceiros; timeout em buscas de saída |
// Fastify: JSON Schema na rota + autenticação preHandler
app.get("/orders/:id", {
schema: { params: { type: "object", properties: { id: { type: "string", format: "uuid" } } } },
preHandler: [authenticate, authorizeOrderRead],
}, handler);# Gera OpenAPI e compara em PR
npx @redocly/cli lint openapi.yamlgrep app.get, app.post em CI.req.user de middleware opcional - rota aberta se o middleware for pulado. Correção: requireAuth explícito por rota protegida.| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
| Zod manual + middleware | Controle total, serviços pequenos | Grande aplicativo NestJS com pipes integrados |
| NestJS Guards + Pipes | Authz orientada a decoradores | Greenfield não-Nest |
| Fastify JSON Schema | Validação crítica de desempenho | Equipe prefere apenas Zod |
| Autenticação de gateway de API | Política de borda centralizada | Ainda precisa de verificações BOLA no aplicativo |
Sim, na prática. Desenvolvedores autenticam usuários, mas esquecem de verificar se eles possuem o :id no caminho.
Sim para BOLA, autenticação e SSRF. Limites de taxa podem ser mais flexíveis, mas limites de recursos ainda importam.
A lista de API é específica para backends REST/GraphQL. Combine com Cabeçalhos de Segurança e CORS para clientes do navegador.
Sim. BOLA se torna autorização em nível de campo; consultas em lote são consumo de recursos API4.
Testes de integração: o token do usuário A não pode ler o recurso do usuário B por ID. Automatize em CI.
Escalone chaves por tenant e por operação. Rotacione e audite o uso. Nunca passe em strings de consulta.
Parcialmente - é risco de dependência. Adicione Helmet, revisão de configuração e testes de penetração para API8 completo.
Use @UseGuards em controladores, não em métodos individuais inconsistentes. Pipe de validação global com whitelist: true.
Versões da Stack: Esta página foi escrita para Node.js 24.18.0 (LTS Ativo), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, e NestJS 11.
Revisado por Chris St. John·Última atualização: 19 de jul. de 2026