Untuk mencegah injection atau abuse, harus ada validasi ketat dan kontrol akses saat Next.js menerima payload body, query, atau header. Next.js: Validasi Input, Secret Handling, dan Rate Limit API Route menguraikan solusi praktis agar App Router dan API Route menangani input berisiko, menjaga secret runtime, serta mengontrol akses lewat rate limit.

Panduan ini juga menunjukkan bagaimana middleware, edge function, dan manajemen operasi berkelanjutan berperan dalam menjaga API tetap aman dan observabel.

Validasi Input di Next.js App Router dan API Route

Validasi input bukan sekadar memastikan format JSON benar, tetapi juga membatasi nilai, menghindari injection, dan memaksakan kontrak data. Gunakan library schema seperti Zod atau Yup untuk validasi body, query, dan header pada satu titik terpusat.

Contoh API route (App Router) dengan Zod untuk memverifikasi body dan query:

import { z } from 'zod';
import { NextResponse } from 'next/server';

const bodySchema = z.object({
  email: z.string().email(),
  message: z.string().min(10),
});

const querySchema = z.object({
  ref: z.optional(z.string().length(8)),
});

export async function POST(request: Request) {
  const query = querySchema.safeParse(Object.fromEntries(request.nextUrl.searchParams));
  if (!query.success) {
    return NextResponse.json({ error: 'Query tidak valid' }, { status: 400 });
  }

  const payload = await request.json();
  const parsed = bodySchema.safeParse(payload);
  if (!parsed.success) {
    return NextResponse.json({ error: parsed.error.flatten().fieldErrors }, { status: 422 });
  }

  // proses lanjutan dengan parsed.data
  return NextResponse.json({ status: 'ok' });
}

Perhatikan bahwa opsi safeParse menghindari exception dan memberikan feedback spesifik. Validasi header juga penting: pastikan header seperti Content-Type dan token auth masuk akal sebelum membongkar body.

Secret Handling dan Pengelolaan Runtime Environment

Secret (API key, database credential) tidak boleh tersimpan di repo. Next.js menyediakan environment variables yang hanya dapat diakses di server (process.env) dan tidak terekspos ke klien.

Praktik terbaik mencakup:

  • Menetapkan prefix NEXT_PUBLIC_ hanya untuk var yang memang harus dipakai di klien; sisanya tetap tanpa prefix dan gunakan hanya di server.
  • Mengamankan proses safe fetch agar semua panggilan ke layanan eksternal memakai secret dari environment, misalnya:
const res = await fetch('https://billing.example.com', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.BILLING_API_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(payload),
});
  • Menyiapkan rotasi secret secara berkala dengan tooling seperti HashiCorp Vault atau Azure Key Vault yang bisa dipanggil saat runtime. Sertakan audit log setiap kali secret disalin atau diperbarui.
  • Memastikan audit logging mencatat akses dari middleware/API route pada secret sensitif (misalnya peristiwa fetch gagal karena token kadaluarsa).
  • Menggunakan next.config.js untuk memvalidasi struktur environment saat build:
const requiredEnv = ['BILLING_API_TOKEN', 'DATABASE_URL'];
requiredEnv.forEach((key) => {
  if (!process.env[key]) {
    throw new Error(`${key} wajib diatur`);
  }
});

export default {
  // konfigurasi lain...
};

Jika menggunakan serverless atau edge, pastikan provider mendukung rotasi dan audit, lalu update variabel di dashboard sebelum deployment.

Rate Limit API Route agar Abuse tertahan

API rate limit mengurangi risiko brute-force dan DoS terhadap endpoint. Next.js middleware cocok untuk implementasi rate limit yang berdasar IP, user ID, atau kombinasi token bucket.

Contoh middleware sederhana dengan token bucket di edge runtime:

import { NextRequest, NextResponse } from 'next/server';
import { rateLimit } from '@upstash/ratelimit';

const limiter = rateLimit({
  redis: process.env.REDIS_URL,
  limit: 20,
  interval: '1 m',
});

export async function middleware(request: NextRequest) {
  const ip = request.headers.get('x-forwarded-for') ?? request.ip;
  const { success } = await limiter.limit(ip);
  if (!success) {
    return NextResponse.json({ error: 'Terlalu banyak permintaan' }, { status: 429 });
  }
  return NextResponse.next();
}

Meskipun Redis dan Upstash adalah contoh, prinsipnya bisa diterapkan dengan local store atau database yang mendukung TTL. Penting untuk menempatkan middleware di layer sebelum API route diproses dan menyesuaikan limit untuk rute sensitif.

Untuk operasi distribusi token bucket, pertimbangkan varian yang mencatat timestamp terakhir dan jumlah token di Redis atau database cepat dengan TTL. Pastikan observability mencatat rate limit hits untuk memudahkan debugging.

Operasional Berkelanjutan dan Best Practice

Penguatan security tidak berhenti di deployment. Tetap lakukan:

  • Monitoring endpoint (misalnya menggunakan Prometheus atau Vercel log) untuk mengetahui error 4xx/5xx akibat rate limit atau validasi.
  • Audit log untuk perubahan secret serta akses API yang mencurigakan (misalnya volume request tiba-tiba tinggi).
  • Review dependency security (misalnya pembaruan Zod, middleware, atau library lain yang digunakan untuk validasi dan rate limit).
  • Automated testing untuk validasi input dan rate limit (contoh: tests unit memanggil API dengan payload valid/invalid dan memastikan response sesuai).
  • Skrip npm run lint plus npm run test di pipeline CI untuk memastikan tim mematuhi validation schema yang telah dibangun.

Jika menggunakan App Router, pertimbangkan menempatkan middleware di folder middleware.ts yang sama untuk semua API route, sehingga rate limit dan validasi bisa diterapkan secara konsisten.

Dengan pendekatan ini, Next.js bisa menjadi platform API yang tangguh terhadap injection, leakage secret, maupun abuse dari sisi trafik.