EmpiezaTuSaaS

Rate Limiting

Protege tus endpoints contra abuso con rate limiting

Rate Limiting

Sin rate limiting, un atacante puede hacer miles de peticiones por segundo a tus API routes: fuerza bruta en login, spam en formularios o agotar tu cuota de Stripe/Resend.

Stack recomendado

Usamos Upstash Redis con @upstash/ratelimit. Es serverless, funciona perfecto con Vercel y tiene un generous free tier.

Setup

Crear base de datos en Upstash

  1. Ve a upstash.com y crea una cuenta
  2. Click en Create Database
  3. Selecciona la region mas cercana a tu deploy (ej: eu-west-1 para Europa)
  4. Copia las credenciales

Agregar variables de entorno

.env.local
UPSTASH_REDIS_REST_URL="https://xxx.upstash.io"
UPSTASH_REDIS_REST_TOKEN="AXxx..."

Instalar dependencias

npm install @upstash/redis @upstash/ratelimit

Crear utilidad de rate limiting

lib/rate-limit.ts
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";

const redis = new Redis({
  url: process.env.UPSTASH_REDIS_REST_URL!,
  token: process.env.UPSTASH_REDIS_REST_TOKEN!,
});

// 10 peticiones por 10 segundos por IP
export const ratelimit = new Ratelimit({
  redis,
  limiter: Ratelimit.slidingWindow(10, "10 s"),
  analytics: true,
  prefix: "ratelimit",
});

// Rate limit mas estricto para auth
export const authRatelimit = new Ratelimit({
  redis,
  limiter: Ratelimit.slidingWindow(5, "60 s"),
  analytics: true,
  prefix: "ratelimit:auth",
});

// Rate limit para webhooks (mas permisivo)
export const webhookRatelimit = new Ratelimit({
  redis,
  limiter: Ratelimit.slidingWindow(100, "60 s"),
  analytics: true,
  prefix: "ratelimit:webhook",
});

Usar en API routes

Proteger un endpoint

app/api/contact/route.ts
import { NextRequest, NextResponse } from "next/server";
import { ratelimit } from "@/lib/rate-limit";

export async function POST(request: NextRequest) {
  // Identificar al usuario por IP
  const ip = request.headers.get("x-forwarded-for") ?? "127.0.0.1";

  const { success, limit, reset, remaining } = await ratelimit.limit(ip);

  if (!success) {
    return NextResponse.json(
      { error: "Demasiadas peticiones. Intenta de nuevo mas tarde." },
      {
        status: 429,
        headers: {
          "X-RateLimit-Limit": limit.toString(),
          "X-RateLimit-Remaining": remaining.toString(),
          "X-RateLimit-Reset": reset.toString(),
        },
      }
    );
  }

  // ... procesar la peticion
  return NextResponse.json({ success: true });
}

Proteger rutas de autenticación

app/api/auth/login/route.ts
import { NextRequest, NextResponse } from "next/server";
import { authRatelimit } from "@/lib/rate-limit";

export async function POST(request: NextRequest) {
  const ip = request.headers.get("x-forwarded-for") ?? "127.0.0.1";

  const { success } = await authRatelimit.limit(ip);

  if (!success) {
    return NextResponse.json(
      { error: "Demasiados intentos de login. Espera 1 minuto." },
      { status: 429 }
    );
  }

  // ... lógica de autenticación
}

Rate limiting en Middleware

Para proteger multiples rutas a la vez, puedes usar el middleware de Next.js:

middleware.ts
import { NextRequest, NextResponse } from "next/server";
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";

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

export async function middleware(request: NextRequest) {
  // Solo aplica rate limiting a rutas de API
  if (request.nextUrl.pathname.startsWith("/api")) {
    const ip = request.headers.get("x-forwarded-for") ?? "127.0.0.1";
    const { success } = await ratelimit.limit(ip);

    if (!success) {
      return NextResponse.json(
        { error: "Rate limit exceeded" },
        { status: 429 }
      );
    }
  }

  return NextResponse.next();
}

export const config = {
  matcher: "/api/:path*",
};

El middleware se ejecuta en el Edge Runtime. Verifica que tus dependencias sean compatibles. @upstash/redis y @upstash/ratelimit funcionan en Edge sin problemas.

Algoritmos disponibles

AlgoritmoUso recomendado
slidingWindowUso general, distribuye las peticiones de forma uniforme
fixedWindowMas simple, resetea el contador en intervalos fijos
tokenBucketPermite rafagas cortas seguidas de un ritmo constante
// Sliding Window: 10 peticiones cada 10 segundos
Ratelimit.slidingWindow(10, "10 s")

// Fixed Window: 100 peticiones por minuto
Ratelimit.fixedWindow(100, "60 s")

// Token Bucket: 10 tokens, se recarga 1 por segundo
Ratelimit.tokenBucket(10, "1 s", 10)

Limites recomendados por tipo de endpoint

EndpointLimiteVentana
API general20 peticiones10 segundos
Login / Registro5 peticiones60 segundos
Envio de emails3 peticiones60 segundos
Checkout de Stripe5 peticiones60 segundos
Webhooks100 peticiones60 segundos

Upstash ofrece 10,000 peticiones/dia gratis. Mas que suficiente para un SaaS en etapa inicial.

On this page