1. Alarm Tengah Malam: Saat Layanan Produksi Mulai Tumbang
Pukul 02.14 WIB. PagerDuty di sebelah bantal bergetar hebat, merobek keheningan malam dengan sirene bernada tinggi yang sudah dihafal di luar kepala oleh setiap Site Reliability Engineer. Belum sempat nyawa terkumpul sepenuhnya, layar ponsel sudah dibanjiri notifikasi merah dari sistem monitoring Prometheus: CPU Utilization di klaster backend Node.js dan edge Nginx melonjak dari rata-rata 12% langsung menempel di angka 99.8% tanpa ampun. Di dashboard Grafana, grafik Latency (P99) yang tadinya tidur manis di bawah 45 milidetik tiba- detik melompat vertikal menembus 14.000 milidetik. Request dari Cloudflare mulai berguguran dengan error code 504 Gateway Time-out.
Panik? Sedikit, tapi sebagai orang yang sudah belasan tahun mengawal infrastruktur skala besar, kepanikan adalah kemewahan yang tidak boleh dibayar. Saya langsung melompat dari tempat tidur, membuka laptop ThinkPad yang tergeletak di meja, dan melakukan SSH kilat ke bastion host produksi. Ada yang tidak beres dengan lalu lintas web kita malam ini. Ini bukan sekadar lonjakan traffic organik dari flash sale atau bot crawler biasa. Ini adalah serangan senyap yang sedang mencekik jantung infrastruktur web server kita perlahan-lahan.
Sistem web modern kita ditopang oleh ekosistem yang cukup kompleks: Nginx sebagai reverse proxy dan SSL terminator di garis terdepan, memfilter request sebelum diteruskan ke PHP-FPM dan layanan core berbasis Go, sementara ModSecurity berdiri sebagai benteng Web Application Firewall (WAF) dengan setumpuk aturan reguler ekspresi (regex). Ketika WAF yang seharusnya menjadi perisai justru menjadi titik kegagalan tunggal, kita tahu bahwa masalah ini tidak akan selesai hanya dengan me-restart layanan. Kita harus masuk lebih dalam ke dalam perut sistem untuk melihat apa yang sedang terjadi di balik layar, mengarahkan kita langsung pada jejak digital pertama yang ditinggalkan oleh si penyerang.
2. Jejak Digital: Menelusuri Anomali Log & Lonjakan Metrik
Masuk ke terminal server edge, langkah pertama saya adalah memeriksa baris demi baris log akses Nginx menggunakan tail -n 100 /var/log/nginx/access.log. Alih-alih melihat pola serangan brute force standar seperti injeksi SQL klasik atau serangan path traversal yang berisik, log justru tampak sangat bersih dari kejauhan. Namun, ada satu kejanggalan yang langsung mencuri perhatian mata seorang engineer berpengalaman: rentetan request HTTP GET dan POST dengan parameter query string yang panjangnya tidak masuk akal, dipenuhi oleh karakter spesial dan simbol berulang yang tampak acak.
Untuk membedah lebih detail, saya melempar perintah awk kilat untuk memetakan distribusi panjang URL yang masuk ke server:
awk '{print $7}' /var/log/nginx/access.log | awk '{print length($0), $0}' | sort -n -r | head -n 20
Hasilnya mengejutkan. Ada payload string sepanjang lebih dari 4.000 karakter yang disisipkan pada parameter pencarian produk. Yang lebih menarik lagi, setiap kali request dengan payload terkutuk ini masuk, proses worker Nginx dan ModSecurity langsung mengalami lonjakan penggunaan CPU hingga 100% pada satu inti (core) tunggal secara persisten. Ini adalah ciri khas klasik dari sebuah perangkap komputasi: Regular Expression Denial of Service (ReDoS).
[!WARNING] Jangan pernah meremehkan string input yang panjang pada parameter query string. Penyerang modern menggunakan string yang dirancang secara matematis untuk mengeksploitasi kelemahan mesin pencocokan regex di dalam WAF atau aplikasi backend.
Untuk membuktikan hipotesis ini, saya melompat ke mesin pengujian lokal dan mulai memprofilkan performa regex menggunakan skrip benchmark sederhana. Di sinilah akar masalah yang sebenarnya mulai tersingkap terang benderang, menuntun kita pada mekanika kelam di balik algoritma pencocokan pola.
3. Membongkar Biang Kerok: Akar Masalah yang Sebenarnya
Untuk memahami mengapa satu baris string bisa melumpuhkan server, kita harus membongkar apa yang terjadi di balik kap mesin mesin regex (regex engine). Sebagian besar bahasa pemrograman dan modul WAF menggunakan mesin regex berbasis Nondeterministic Finite Automaton (NFA) yang mendukung fitur backtracking. Masalahnya muncul ketika sebuah pola regex dirancang secara buruk dan dihadapkan pada input yang memiliki struktur ambigu.
Mari kita lihat contoh aturan WAF lama yang menjadi biang keladi bencana malam ini. Aturan ModSecurity untuk mendeteksi potensi XSS atau malicious script menggunakan pola seperti ini:
^([a-zA-Z0-9]+)*([\s\S]*)([a-zA-Z0-9]+)*$
Pola di atas terlihat tidak berbahaya bagi mata awam. Namun, ketika mesin NFA membaca string input yang panjang dan sengaja dibuat tanpa kecocokan di bagian akhir (misalnya string yang diakhiri dengan karakter spesial alih-alih alfanumerik), mesin tersebut akan mencoba setiap kemungkinan jalur percabangan pencocokan sebelum menyerah. Ini dinamakan Catastrophic Backtracking.
[!IMPORTANT] Kompleksitas waktu untuk regex yang rentan terhadap Catastrophic Backtracking bisa melonjak secara eksponensial ($O(2^n)$). Artinya, input sepanjang 50 karakter saja bisa membutuhkan triliunan operasi CPU dan memakan waktu berhari-hari untuk dievaluasi oleh satu thread CPU.
Analogi sederhananya seperti Anda menyuruh seseorang mencari jarum di tumpukan jerami dengan memeriksa setiap helai jerami satu per satu, lalu menyuruhnya mengulang dari awal setiap kali ia salah mengambil jalur. Ketika penyerang mengirimkan ribuan request paralel dengan payload ReDoS ini, pool worker langsung habis terkunci, membuat server sah tidak bisa dilayani. Kita harus segera memadamkan api ini sebelum manajemen pusat terbangun dan menelepon.
4. Tindakan Darurat: Menghidupkan Kembali Layanan dalam Hitungan Menit
Saat insiden sedang berlangsung, prioritas utama bukanlah mencari kesempurnaan arsitektur, melainkan memulihkan ketersediaan layanan (service availability) secepat kilat. Tanpa membuang waktu, saya langsung mengeksekusi rangkaian perintah darurat di terminal untuk memblokir IP penyerang, menambal aturan WAF yang bermasalah, dan merestart pool worker Nginx-ModSecurity.
Berikut adalah one-liner terminal siap salin yang menyelamatkan sistem produksi dalam hitungan detik saat insiden terjadi:
# 1. Isolasi dan blokir IP penyerang secara cepat via iptables
awk '($9 ~ /504/)' /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -nr | head -n 10 | awk '{print $2}' | xargs -I {} iptables -A INPUT -s {} -j DROP
# 2. Hentikan sementara proses worker yang tersangkut (hanging processes)
killall -9 modsecurity_handler
# 3. Timpa file konfigurasi ModSecurity yang rentan dengan regex yang sudah di-hardened (aman)
echo 'SecRule ARGS "@rx ^[a-zA-Z0-9-_\.]{1,100}$" "phase:2,deny,status:403,id:999999"' > /etc/modsecurity/rules.d/hotfix_redos.conf
# 4. Reload konfigurasi Nginx dengan mulus tanpa downtime
nginx -t && systemctl reload nginx
Seketika setelah perintah tersebut dieksekusi, grafik CPU di Prometheus langsung terjun bebas dari 99% kembali ke level normal di kisaran 15%. Latency P99 pulih seketika ke angka di bawah 40 milidetik. Layanan kembali bernapas lega. Namun, pekerjaan kita belum selesai; tindakan darurat hanyalah plester luka. Kita memerlukan kebijakan arsitektural jangka panjang agar insiden serupa tidak pernah terulang kembali di masa depan.
5. Kebijakan Retrospektif: Menambal Celah agar Tak Pernah Terulang
Setelah situasi terkendali, saya mengumpulkan tim engineering untuk melakukan post-mortem blameless session. Kami menyadari bahwa masalah ini berakar dari kurangnya standar validasi regex saat code review dan ketiadaan otomasi pengujian keamanan regex di dalam pipeline CI/CD kita.
Sebagai langkah preventif permanen, kita merombak total pendekatan terhadap regex di seluruh lapisan aplikasi dan infrastruktur:
- Batasi Panjang Input (Input Length Guard): Sebelum masuk ke mesin regex, Nginx dan backend Go/Node.js wajib memvalidasi panjang string maksimum menggunakan parameter
client_max_body_sizedan sanitasi panjang string di tingkat controller. - Gunakan Mesin Regex Berbasis DFA: Beralih dari mesin NFA murni ke mesin berbasis Deterministic Finite Automaton (seperti yang digunakan pada beberapa pustaka modern Go
regexpyang menjamin kompleksitas waktu linear $O(n)$). - Terapkan Linting Regex di CI/CD: Mengintegrasikan tools linter seperti
rcheckatausafe-regexke dalam GitHub Actions pipeline untuk memblokir secara otomatis setiap pull request yang mengandung pola regex rentan backtracking.
Berikut adalah perbandingan nyata antara konfigurasi regex yang berbahaya dan versi yang sudah di-hardened:
# â SALAH & BERBAHAYA: Rentan terhadap Catastrophic Backtracking
SecRule ARGS:q "@rx ^([a-zA-Z0-9]+)*([\s\S]*)([a-zA-Z0-9]+)*$" \
"id:1001,phase:2,deny,status:403,msg:'Potential ReDoS Attack'"
# â
BENAR & AMAN: Menggunakan batas kuantifikasi tegas dan menghindari nested quantifiers
SecRule ARGS:q "@rx ^[a-zA-Z0-9\-_\s]{1,64}$" \
"id:1001,phase:2,deny,status:403,msg:'Strict Safe Validation'"
Dengan aturan baru ini, tidak ada lagi ruang bagi string liar untuk mempermainkan siklus CPU server kita. Namun, keamanan bukanlah destinasi, melainkan proses yang kontinu. Kita harus memasang mata dan telinga ekstra melalui sistem otomasi alarm yang handal.
6. Pasang Alarm: Otomasi Deteksi Dini untuk Tim On-Call
Agar tidak ada lagi alarm tengah malam yang mengejutkan tanpa persiapan, kami membangun sistem deteksi dini berbasis metrik kustom di Prometheus yang diintegrasikan langsung ke kanal Slack tim security dan PagerDuty.
Kita membuat aturan alert rule baru di Prometheus (alert.rules.yml) untuk memantau waktu eksekusi regex dan lonjakan CPU spesifik pada proses WAF:
groups:
- name: redos-detection-rules
rules:
- alert: HighCPUViaWAFRegex
expr: rate(node_cpu_seconds_total{mode="system\