Cara Implementasi Express Rate Limit di Node.js

express-rate-limit adalah pustaka middleware pihak ketiga untuk kerangka kerja Express.js di Node.js yang berfungsi untuk membatasi jumlah permintaan (request) berulang dari alamat IP yang sama ke sebuah server dalam jangka waktu tertentu. Pustaka ini sangat esensial untuk mengamankan API dari serangan brute-force, denial-of-service (DoS), atau penggunaan bot yang berlebihan.

Cara kerjanya adalah dengan mencatat aktivitas IP klien menggunakan penyimpanan memori bawaan (memory store) atau penyimpanan eksternal seperti Redis. Jika jumlah permintaan melampaui batas yang ditentukan (misalnya 100 permintaan per 15 menit), peladen akan menghentikan proses dan mengembalikan kode status HTTP 429 Too Many Requests.

Instalasi dan Konfigurasi Dasar

Untuk memulai, pastikan proyek Node.js Anda sudah terinstal Express. Jalankan perintah terminal berikut untuk memasang paket express-rate-limit:

npm install express-rate-limit

Berikut adalah contoh implementasi dasar dalam kode server Express:

const express = require('express');
const { rateLimit } = require('express-rate-limit');

const app = express();

// Konfigurasi pembatas laju dasar
const limiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15 menit
    max: 100, // Batasi setiap IP hingga 100 permintaan per windowMs
    message: 'Terlalu banyak permintaan dari IP ini, silakan coba lagi setelah 15 menit',
    standardHeaders: true, // Mengirimkan header pembatas laju standar (RateLimit-*)
    legacyHeaders: false, // Menonaktifkan header X-RateLimit-*
});

// Terapkan pembatas laju ke semua rute
app.use(limiter);

app.get('/', (req, res) => {
    res.send('Halo, dunia!');
});

app.listen(3000, () => {
    console.log('Server berjalan pada port 3000');
});

Parameter Konfigurasi Utama

Pustaka ini menyediakan berbagai opsi parameter untuk menyesuaikan kebutuhan keamanan aplikasi Anda. Berikut adalah tabel parameter yang paling sering digunakan:

Parameter Tipe Data Keterangan
windowMs Number Durasi waktu dalam milidetik untuk pelacakan ulang batas permintaan.
max Number / Function Jumlah maksimum permintaan yang diizinkan per IP dalam rentang windowMs.
message String / JSON / Any Respons yang dikirimkan ketika batas terlampaui.
statusCode Number Kode status HTTP yang dikembalikan saat batas terlampaui (default: 429).
skip Function Fungsi untuk melewati (skip) pembatasan berdasarkan kondisi tertentu (misal: IP lokal).
store Object Media penyimpanan data hit (default menggunakan MemoryStore).

Penerapan pada Rute Tertentu (Endpoint Specific)

Seringkali pembatasan tidak perlu diterapkan ke seluruh aplikasi, melainkan hanya pada rute sensitif seperti halaman login atau pendaftaran akun untuk mencegah serangan kredensial.

const { rateLimit } = require('express-rate-limit');

// Pembatasan khusus untuk rute login
const loginLimiter = rateLimit({
    windowMs: 60 * 60 * 1000, // 1 jam
    max: 5, // Batasi 5 kali percobaan login per jam
    message: { status: 429, error: 'Terlalu banyak percobaan login, coba lagi nanti.' },
    standardHeaders: true,
    legacyHeaders: false,
});

// Terapkan hanya pada endpoint /api/login
app.post('/api/login', loginLimiter, (req, res) => {
    // Logika autentikasi di sini
    res.send('Proses login...');
});

Menggunakan Redis untuk Skala Banyak Server (Cluster/Load Balancer)

Secara default, express-rate-limit menggunakan penyimpanan memori lokal. Jika aplikasi Anda berjalan di banyak instans (seperti di Docker, Kubernetes, atau menggunakan load balancer), memori lokal tidak akan sinkron antar server. Anda memerlukan penyimpanan eksternal seperti Redis menggunakan pustaka tambahan rate-limit-redis.

npm install express-rate-limit rate-limit-redis redis

Contoh integrasi dengan Redis:

const { createClient } = require('redis');
const { rateLimit } = require('express-rate-limit');
const { RedisStore } = require('rate-limit-redis');

// Inisialisasi klien Redis
const client = createClient();
client.connect().catch(console.error);

const redisLimiter = rateLimit({
    store: new RedisStore({
        sendCommand: (...args) => client.call(...args),
    }),
    windowMs: 15 * 60 * 1000,
    max: 100,
});

app.use(redisLimiter);

Troubleshooting Masalah IP Asli di Balik Proxy

Jika aplikasi Node.js Anda berada di belakang reverse proxy seperti Nginx, Cloudflare, atau AWS ELB, alamat IP yang terdeteksi oleh Express akan selalu berupa IP lokal peladen (127.0.0.1) atau IP proxy tersebut, bukan IP asli pengguna.

Untuk mengatasi hal ini, Anda harus mengaktifkan pengaturan trust proxy pada aplikasi Express sebelum menerapkan pembatas laju:

// Beritahu Express untuk percaya pada proxy pertama
app.set('trust proxy', 1);

const limiter = rateLimit({
    windowMs: 15 * 60 * 1000,
    max: 100,
});

app.use(limiter);