1. Menu Kita Hari Ini & Alat yang Perlu Disiapkan
Pernahkah layanan backend Node.js atau Go Anda tiba-tiba mengalami lonjakan CPU hingga 100% hanya karena menerima payload JSON yang kelihatannya tidak berbahaya? Di lapangan, saya sering mendapati insiden ini berakar dari satu hal sepele: ekspresi reguler (Regex) yang ditulis sembarangan untuk memvalidasi string input yang panjang.
Dalam 15 menit ke depan, kita akan merakit sistem validasi payload web yang kebal terhadap serangan ReDoS (Regular Expression Denial of Service). Kita tidak akan membuang waktu membahas teori buku teks yang membosankan. Kita langsung terjun ke dapur produksi untuk membedah anatomi kuantifikator rakus, menguji kinerjanya dengan skrip benchmark nyata, dan menerapkan pola aman menggunakan mesin V8 dan RE2.
Sebelum mulai meracik, siapkan dulu alat tempur di terminal Anda:
- Mesin dengan Node.js versi 18+ atau Go 1.20+
- Utility
autocannonatau skrip k6 untuk load testing - Text editor kesayangan Anda
[!IMPORTANT] ReDoS bukan sekadar bug fungsional, ini adalah vektor serangan DoS layer aplikasi yang dapat melumpuhkan seluruh kluster server web Anda tanpa menyentuh batas kapasitas bandwidth jaringan.
Mari kita mulai perjalanan ini dengan memahami peta jalan arsitektur yang akan kita bangun.
2. Peta Jalan Singkat: Apa yang Sedang Kita Rakit
Untuk mengamankan endpoint API dari eksploitasi Regex, kita harus mengubah cara pandang dalam menulis pola validasi. Seringkali, developer menulis regex yang terlihat ringkas namun secara diam-diam memicu backtracking eksponensial di balik layar.
Berikut adalah tahapan praktis yang akan kita lalui:
- Membedah Anatomi ReDoS: Kita lihat langsung bagaimana satu karakter tambahan dalam regex bisa melumpuhkan event loop Node.js.
- Optimasi Kuantifikator Rakus: Mengubah pola greedy dan nested quantifiers menjadi possessive quantifiers atau menggunakan batasan tegas.
- Pengujian Kinerja Pattern: Menjalankan benchmark menggunakan payload beracun untuk membuktikan efektivitas kode baru kita.
[!TIP] Selalu gunakan engine regex non-backtracking seperti RE2 jika bahasa pemrograman Anda mendukungnya, terutama untuk menangani payload string dari pengguna publik.
3. Langkah 1: Mempersiapkan Fondasi & Environment
Kita mulai dengan menyiapkan direktori kerja dan menginstal beberapa pustaka esensial untuk simulasi serangan dan pengujian performa regex. Buka terminal Anda dan jalankan perintah di bawah ini:
mkdir redos-lab && cd redos-lab
npm init -y
npm install express safe-regex
Perhatikan respons instalasi di terminal Anda. Jika paket terpasang tanpa error, itu tanda bahwa fondasi lingkungan kerja kita sudah siap untuk mulai meracik kode validasi yang aman.
Sekarang, mari buat file utama server.js untuk mensimulasikan endpoint yang rentan terhadap ReDoS, lalu kita akan perbaiki bersama-sama.
4. Langkah 2: Meracik Konfigurasi Inti Tanpa Basa-basi
Mari kita tulis kode server Express yang menggunakan regex rentan secara sengaja. Buat file server.js dan masukkan kode berikut:
const express = require('express');
const app = express();
app.use(express.json());
// CONTOH RENTAN (Vulnerable Regex): Nested quantifier dengan overlapping
// Pola ini memicu backtracking katastrofik pada input yang tidak cocok.
const vulnerableRegex = /^([a-zA-Z0-9]+)*$/;
app.post('/validate', (req, res) => {
const { payload } = req.body;
const startTime = process.hrtime();
// Eksekusi regex berbahaya pada input panjang yang dirancang khusus
const isValid = vulnerableRegex.test(payload);
const elapsed = process.hrtime(startTime);
const elapsedMs = (elapsed[0] * 1000) + (elapsed[1] / 1e6);
res.json({
success: true,
isValid,
executionTimeMs: elapsedMs
});
});
app.listen(3000, () => {
console.log('Server Lab ReDoS berjalan di port 3000');
});
Jalankan server tersebut dengan perintah node server.js. Perhatikan bagaimana server merespons dengan cepat untuk input normal. Namun, tunggu sampai kita masuk ke sesi uji rasa.
5. Langkah 3: Sentuhan Akhir Keamanan & Optimasi
Sekarang kita perbaiki celah tersebut. Kita ganti pola regex yang menggunakan nested quantifier dengan struktur yang tegas, atau menggunakan pustaka alternatif yang membatasi waktu eksekusi.
Buat file baru bernama secure-server.js sebagai pembanding:
const express = require('express');
const app = express();
app.use(express.json());
// POLA AMAN: Batasan tegas tanpa nested quantifier yang memicu backtracking
// Menggunakan anchor yang jelas dan membatasi panjang input
const secureRegex = /^[a-zA-Z0-9]{1,100}$/;
app.post('/validate-secure', (req, res) => {
const { payload } = req.body;
if (typeof payload !== 'string' || payload.length > 100) {
return res.status(400).json({ error: 'Payload tidak valid atau terlalu panjang' });
}
const startTime = process.hrtime();
const isValid = secureRegex.test(payload);
const elapsed = process.hrtime(startTime);
const elapsedMs = (elapsed[0] * 1000) + (elapsed[1] / 1e6);
res.json({
success: true,
isValid,
executionTimeMs: elapsedMs
});
});
app.listen(3001, () => {
console.log('Server Aman berjalan di port 3001');
});
[!WARNING] Jangan pernah mempercayai panjang input dari payload web tanpa melakukan sanitasi atau pembatasan ukuran awal di level reverse proxy seperti Nginx atau WAF.
6. Tes Rasa: Memastikan Semuanya Berjalan Sempurna
Mari kita uji ketahanan kode kita menggunakan payload beracun (malicious payload) yang dirancang untuk memicu backtracking. Buat file skrip uji test.js:
const http = require('http');
// Payload beracun: deretan karakter valid diikuti oleh satu karakter invalid di akhir
// Menyebabkan engine mencoba seluruh kombinasi backtracking.
const maliciousPayload = 'a'.repeat(30) + '!';
const data = JSON.stringify({ payload: maliciousPayload });
const options = {
hostname: 'localhost',
port: 3000,
path: '/validate',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
}
};
const req = http.request(options, (res) => {
let body = '';
res.on('data', (chunk) => body += chunk);
res.on('end', () => {
console.log('Hasil Endpoint Rentan:', body);
});
});
req.write(data);
req.end();
Jalankan node test.js dan amati lonjakan waktu eksekusi pada port 3000 bandingkan dengan port 3001. Anda akan melihat perbandingan latensi yang masif, membuktikan bahwa optimasi regex kita berhasil meredam potensi DoS.
7. Pertolongan Pertama: Jika Terjadi Kendala Kecil
Jika dalam praktiknya Anda masih mendapati proses backend melambat atau mengalami timeout, lakukan pemeriksaan cepat berikut:
- Periksa Nginx Upstream Timeout: Pastikan timeout proxy Nginx tidak terlalu longgar sehingga koneksi menggantung terlalu lama.
- Gunakan Safe-Regex Linter: Integrasikan modul
safe-regexke dalam pipeline CI/CD Anda untuk memblokir deployment kode yang mengandung pola regex berbahaya secara otomatis. - Monitor Penggunaan CPU: Gunakan Prometheus dan Grafana untuk memantau metrik penggunaan CPU per core, bukan hanya rata-rata keseluruhan server.