Next.js
Protégez une application Next.js avec @zarex/next, dans un route handler ou pour toutes les routes.
@zarex/next fonctionne dans les route handlers et dans le fichier qui intercepte toutes les requêtes (proxy.ts à partir de Next.js 16, middleware.ts avant). Il n'utilise que les objets Request et Response standard.
Installation
npm install @zarex/nextAjoutez votre clé dans .env.local (sans préfixe NEXT_PUBLIC_) :
ZAREX_KEY=zarex_test_...Protéger un route handler
import { withZarex, shield, rateLimit } from "@zarex/next";
export const GET = withZarex(
{
key: process.env.ZAREX_KEY!,
ipSource: "vercel",
rules: [shield(), rateLimit({ max: 100, window: "1m" })],
},
async () => Response.json({ produits: [] })
);Une requête refusée reçoit automatiquement 403, ou 429 avec Retry-After, sans que votre handler soit appelé.
Protéger toutes les routes
import { NextResponse } from "next/server";
import { zarexNext, shield, rateLimit } from "@zarex/next";
const guard = zarexNext({
key: process.env.ZAREX_KEY!,
ipSource: "vercel",
rules: [shield(), rateLimit({ max: 100, window: "1m" })],
});
export async function proxy(request: Request) {
return (await guard(request)) ?? guard.finalize(NextResponse.next(), request);
}guard(request) renvoie la réponse de refus, ou null si la requête peut continuer.
N'oubliez pas finalize
Si vous activez secureHeaders ou responseGuard, appelez guard.finalize(...) aussi sur la réponse autorisée, comme ci-dessus : sinon ces protections ne s'appliquent jamais au trafic autorisé. Avec withZarex, c'est automatique.
L'adresse IP du visiteur
Next.js ne donne jamais l'adresse de la connexion : Zarex la lit dans un en-tête écrit par votre hébergeur ou par votre proxy.
| Hébergement | ipSource |
|---|---|
| Vercel | Rien à faire (détecté automatiquement), ou "vercel". |
| Fly.io | Rien à faire (détecté automatiquement), ou "fly". |
| Cloudflare Workers ou Pages | Rien à faire (détecté automatiquement), ou "cloudflare-workers". |
| VPS ou Docker derrière nginx ou Caddy | { header: "x-real-ip" }, l'en-tête écrit par votre proxy. |
| Cloudflare devant votre serveur | { header: "cf-connecting-ip" } |
Ailleurs, sans ipSource, l'application refuse de démarrer plutôt que de deviner.
Pas de { proxies } ni de "cloudflare" avec Next.js
Ces réglages ont besoin de l'adresse de la connexion, que Next.js ne fournit pas : les requêtes passeraient sans être vérifiées. Avec { header }, le proxy doit écraser l'en-tête, et l'application ne doit être joignable que par lui. Configuration nginx et Caddy : voir L'adresse IP du visiteur.
En local
next dev ne fournit aucun en-tête d'adresse : sans précaution, les requêtes passent sans être vérifiées (un avertissement l'indique dans les logs). Avec ipSource: { header: "x-real-ip" }, testez en ajoutant l'en-tête vous-même :
curl -H "X-Real-IP: 41.0.0.1" "http://localhost:3000/api/produits?id=1%27%20OR%20%271%27=%271"Données de formulaire
withZarex lit la requête avant votre handler : pour valider un e-mail, un téléphone ou un texte saisi dans un formulaire, utilisez plutôt createZarex et appelez protect vous-même, avec les données déjà lues.
"use server";
import { headers } from "next/headers";
import { createZarex, emailValidation, rateLimit } from "@zarex/next";
const zarex = createZarex({
key: process.env.ZAREX_KEY!,
ipSource: "vercel",
rules: [rateLimit({ max: 5, window: "10m" }), emailValidation()],
});
export async function inscrire(email: string) {
const h = await headers();
const decision = await zarex.protect(
{ method: "POST", path: "/inscription", headers: h },
{ email }
);
if (decision.denied) return { ok: false };
// … créer le compte
return { ok: true };
}Personnaliser le refus
withZarex(
{
key: process.env.ZAREX_KEY!,
rules: [shield()],
onDeny: (request, decision) =>
Response.json({ erreur: "Requête refusée", id: decision.id }, { status: 403 }),
},
handler
);onDeny reçoit la décision complète et doit toujours renvoyer une Response : c'est elle qui est envoyée au visiteur à la place de votre handler. Si elle n'en renvoie pas (un return oublié, par exemple), le SDK envoie la réponse de refus par défaut et le signale dans vos logs : la requête reste bloquée (depuis la version 0.1.4). onDegraded(request, decision) est appelé quand Zarex n'a pas pu décider et que la requête a été laissée passer.