Sécuriser une route API Next.js exposée publiquement

Une route API Next.js déployée sur Vercel est accessible dès sa mise en production, sans barrière par défaut. Aucun WAF, aucun rate limiting, aucune authentification ne sont activés nativement. Si cette route traite des données sensibles, déclenche des actions métier ou consomme des ressources coûteuses (appels LLM, envoi d'emails, écriture en base), l'absence de contrôle expose l'infrastructure à des abus immédiats : scraping, credential stuffing, épuisement de quota, ou simple déni de service.

Cet article couvre les mesures concrètes à mettre en place, dans l'ordre de priorité.

1. Authentifier chaque requête

Une route publique ne signifie pas une route ouverte. Trois mécanismes s'appliquent selon le contexte :

API Key statique pour les intégrations serveur-à-serveur (webhooks entrants, partenaires B2B) :

export async function POST(req: Request) {
  const apiKey = req.headers.get("x-api-key");
  if (apiKey !== process.env.PARTNER_API_KEY) {
    return new Response("Unauthorized", { status: 401 });
  }
  // logique métier
}

Ne jamais comparer les clés avec === en production sur des secrets longs sans précaution — utilisez crypto.timingSafeEqual pour éviter les attaques par timing sur des endpoints critiques.

Signature HMAC pour les webhooks (Stripe, GitHub, etc. procèdent ainsi) : le corps de la requête est signé côté émetteur, et vous vérifiez la signature avant tout traitement.

import { createHmac, timingSafeEqual } from "crypto";

function verifySignature(payload: string, signature: string, secret: string) {
  const expected = createHmac("sha256", secret).update(payload).digest("hex");
  return timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

JWT ou session token pour les appels initiés depuis un client authentifié. Vérifiez systématiquement l'expiration, l'issuer et l'audience, pas seulement la signature.

2. Limiter le débit avant que la logique métier s'exécute

Le rate limiting doit intervenir en amont, avant tout traitement coûteux. Sur Vercel, Upstash Redis avec @upstash/ratelimit est le standard le plus simple à opérer, y compris en environnement Edge :

import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";

const ratelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(10, "60 s"),
});

export async function POST(req: Request) {
  const ip = req.headers.get("x-forwarded-for") ?? "anonymous";
  const { success, remaining } = await ratelimit.limit(ip);

  if (!success) {
    return new Response("Too Many Requests", {
      status: 429,
      headers: { "Retry-After": "60" },
    });
  }
  // suite du traitement
}

Deux points d'attention : x-forwarded-for peut être falsifié si votre reverse proxy ne l'assainit pas — sur Vercel, préférez req.headers.get("x-real-ip") ou l'IP fournie par le contexte Edge. Et le rate limiting par IP seule ne suffit pas si l'attaquant dispose d'un pool d'adresses : combinez-le avec une limite par clé API ou par compte utilisateur.

3. Valider strictement les entrées, sans exception

Toute donnée entrante — body, query params, headers — doit être validée par un schéma explicite avant d'atteindre la logique métier. Zod est le choix par défaut dans l'écosystème Next.js :

import { z } from "zod";

const schema = z.object({
  email: z.string().email(),
  amount: z.number().positive().max(10000),
});

export async function POST(req: Request) {
  const body = await req.json();
  const result = schema.safeParse(body);

  if (!result.success) {
    return Response.json({ error: result.error.flatten() }, { status: 400 });
  }
  // result.data est typé et validé
}

N'exposez jamais le détail des erreurs de validation en production si elles révèlent la structure interne (noms de champs sensibles, contraintes métier). Loggez le détail côté serveur, renvoyez un message générique côté client.

4. Limiter la surface d'erreur exposée

Les stack traces, messages d'erreur de librairie ou codes SQL ne doivent jamais transiter dans la réponse HTTP. Encapsulez

Le Template Puppeteer B2B, gratuit

Un script d'automatisation prêt à l'emploi pour vos scrapers et générateurs de PDF B2B. Envoyé par e-mail, sans spam.

Partenaire

Hébergez vos APIs sur une infrastructure rapide

Hostinger propose un hébergement cloud et VPS haute performance avec NVMe, CDN intégré et déploiement Git — idéal pour vos back-ends et APIs JSON.