Problema
Chaves de terceiros vazam no client bundle, route handlers aceitam JSON sem validação e cookies sensíveis são expostos a XSS por má configuração. Em full stack moderno, o ataque surface é front + BFF + API ao mesmo tempo.
Solução
Regra de ouro: segredos e políticas de confiança só no servidor (RSC, Server Actions, Route Handlers). Validar todo input com schema (Zod). Separar “API pública” de “API interna”. Preferir chamadas server-to-server com auth mútua ou tokens de curta duração.
Arquitetura
Browser → Next (RSC / Actions) → serviço interno / DB
↘ (somente dados já autorizados)
- BFF no Next agrega e reduz tokens expostos.
- Route Handlers para webhooks e integrações que precisam de método HTTP explícito.
- CORS restritivo apenas onde há client externo legítimo.
Código
// app/api/quote/route.ts
import { z } from "zod";
import { NextResponse } from "next/server";
const bodySchema = z.object({
sku: z.string().min(1).max(64),
qty: z.number().int().positive().max(999),
});
export async function POST(req: Request) {
const json = await req.json().catch(() => null);
const parsed = bodySchema.safeParse(json);
if (!parsed.success) {
return NextResponse.json({ error: "Invalid payload" }, { status: 400 });
}
const price = await pricingService.quote(parsed.data); // usa API_KEY só no servidor
return NextResponse.json(price);
}Nunca:
const res = await fetch("https://partner.com", {
headers: { Authorization: `Bearer ${process.env.PARTNER_SECRET}` },
});…em componente com "use client" — o secret pode ir parar no bundle.
Performance
Validação barata primeiro; rate limit na borda (middleware ou gateway); payloads compactos. Cache GET idempotentes com Cache-Control explícito.
Melhorias futuras
mTLS entre serviços; WAF; assinatura de webhooks; auditoria de mutations sensíveis.
Conclusão
Segurança no Next é modelagem de confiança por camada. Mostrar isso no portfólio comunica maturidade full stack real, não tutorial de fetch.