Pendahuluan: Kenapa Hardening API Routes Next.js Penting

Dalam Next.js App Router, API Routes sering menjadi pintu masuk untuk operasi sensitif. Untuk memastikan endpoint tetap hanya diakses oleh klien yang sah, langkah-langkah validasi, proteksi sesi, dan mitigasi abuse harus diterapkan secara konsisten. Artikel ini langsung menjawab: bagaimana cara memisahkan kredensial, memvalidasi payload dan file upload, membatasi sesi dengan cookie aman, serta menambahkan rate limit di edge middleware agar API tetap tangguh.

Semua pembahasan akan disertai contoh praktis dan catatan trade-off agar implementasi bisa disesuaikan dengan kebutuhan nyata.

Memisahkan Credentials dari Environment

Langkah pertama hardening adalah menjaga agar kredensial tidak tersimpan di kode sumber. Di Next.js, gunakan .env.local untuk nilai sensitif seperti DATABASE_URL, API_SECRET, atau credential storage external. Jangan hardcode di route handlers atau komponen. Gunakan modul utilitas yang memvalidasi keberadaan variabel sebelum dipakai.

Contoh pendekatan:

export function getSecretConfig() {
  const secret = process.env.API_SECRET;
  if (!secret) throw new Error('API_SECRET belum diset');
  return { secret };
}

Tindakan ini membatasi risiko eksposur saat repository dibagikan atau ketika konfigurasi di-deploy ke lingkungan staging/production yang berbeda.

Hardening API Routes Next.js: Validasi Payload dan Upload

Pada level API route, validasi dua arah (payload dan file upload) mencegah injeksi data atau ukuran tidak terkontrol. Berikut struktur minimal handler di App Router:

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

const bodySchema = z.object({
  title: z.string().min(5),
  description: z.string().optional(),
});

export async function POST(request) {
  const json = await request.json();
  const parsed = bodySchema.safeParse(json);
  if (!parsed.success) {
    return NextResponse.json({ error: 'Payload tidak valid' }, { status: 422 });
  }

  // Tambahkan validasi file size melalui form-data parser jika diperlukan
  return NextResponse.json({ message: 'Payload diterima' });
}

Gunakan library seperti Zod atau Yup untuk validasi yang eksplisit. Untuk upload file via multipart, batasi ukuran di middleware atau edge function (misalnya dengan membatasi Content-Length), dan simpan file ke storage terpisah setelah memindai konten.

Trade-off: penambahan validasi meningkatkan latensi karena parsing data ekstra, tetapi secara drastis mengurangi permukaan serangan.

Session Secure dengan HttpOnly Cookie dan Rotating Token

Untuk session yang aman, gunakan HttpOnly secure cookies agar JavaScript di sisi klien tidak bisa membaca token. Struktur cookie di Next.js App Router contohnya:

import { cookies } from 'next/headers';

export function setSecureSession(value) {
  const cookieStore = cookies();
  cookieStore.set({
    name: 'sessionId',
    value,
    httpOnly: true,
    secure: true,
    path: '/',
    sameSite: 'lax',
  });
}

Implementasi rotating token bisa dilakukan dengan menyimpan token awal di storage (misal Redis) dan menggantinya setiap kali request sah diproses. Jika token yang lama digunakan lagi, segera tandai sebagai tidak valid. Strategi ini menutup celah replay attack.

Catatan debugging: gunakan log server-side untuk memeriksa cookie yang diterima, jangan mengandalkan console client untuk HttpOnly cookie.

Trade-off: Rotasi token memerlukan penyimpanan state tambahan dan sinkronisasi antar instance, terutama jika menggunakan serverless dan cache terdistribusi.

Rate Limit dan Deteksi Abuse di Edge Middleware

Edge middleware cocok untuk mendeteksi pola abuse sebelum mencapai API Routes. Berikut contoh minimal yang menggunakan cache sederhana (misalnya Memcached atau EdgeKV) untuk menghitung request per IP:

import { NextResponse } from 'next/server';

const LIMIT = 60;
const WINDOW_MS = 60 * 1000;

export async function middleware(request) {
  const ip = request.ip || 'anonymous';
  const key = `rl:${ip}`;
  const current = Number(await fetchRate(key));

  if (current >= LIMIT) {
    return NextResponse.json({ error: 'Rate limit terlampaui' }, { status: 429 });
  }

  await incrementRate(key, WINDOW_MS);
  return NextResponse.next();
}

Implementasi nyata harus menggantikan fetchRate dan incrementRate dengan store yang mendukung TTL. Deteksi abuse bisa diperluas dengan membandingkan user agent, frekuensi upload, atau geolokasi abnormal.

Trade-off: Rate limit di edge menambah latensi kecil tapi mencegah beban berlebih di backend. Pastikan middleware bersifat idempotent dan tidak memanggil route handler saat limit tercapai.

Checklist Implementasi Hardening

  • Siapkan utilitas untuk memvalidasi keberadaan kredensial di environment sebelum server mulai.
  • Terapkan validasi schema di setiap API route (payload dan upload) dan tangani error dengan status kustom.
  • Gunakan HttpOnly secure cookie dengan atribut SameSite yang sesuai dan rotasi token session secara berkala.
  • Pasang middleware edge untuk rate limit, deteksi abuse, dan logging request abnormal.
  • Catat trade-off kinerja, terutama latensi parsing data dan komunikasi ke store sesi yang terdistribusi.
  • Uji dengan skenario invalid payload, token kadaluarsa, dan threshold rate limit sebelum deploy.

Dengan pendekatan ini, API Routes di Next.js akan lebih tahan terhadap input jahat, session hijacking, dan serangan distribusi.