Dampak awal: hanya request POST tertentu yang ditolak
Urutan investigasi: dari laporan 403 ke baris log ModSecurity
SecAuditLogParts, isi request body. Lokasi kedua file ini beda-beda per distro dan panel. Cara paling aman adalah mencari direktif SecAuditLog dan lokasi error log di konfigurasi server yang sedang kamu tangani.
Untuk triase awal, error log biasanya sudah cukup:
BASH
# Cari entri ModSecurity yang menyebut path form (sesuaikan path log dan URI)
grep 'ModSecurity' /var/log/apache2/error.log | grep '/kontak' | tail -n 20
# Ambil semua baris dengan unique_id yang sama untuk melihat rule penyumbang skor
grep 'unique_id "CONTOH_UNIQUE_ID"' /var/log/apache2/error.logunique_id. Field inilah yang menyatukan beberapa baris log menjadi satu cerita, dan juga yang menghubungkan error log dengan entri audit log yang sama.
Titik terang: rule 949110 bukan pelaku sebenarnya
unique_id yang sama.
Contoh format output (disederhanakan, bukan dari insiden nyata):
TEXT
ModSecurity: Warning. ... [id "942100"] [msg "SQL Injection Attack Detected via libinjection"] [data "Matched Data: ... found within ARGS:pesan: ..."] [uri "/kontak/"] [unique_id "CONTOH_UNIQUE_ID"]
ModSecurity: Access denied with code 403 (phase 2). ... [id "949110"] [msg "Inbound Anomaly Score Exceeded (Total Score: 5)"] [uri "/kontak/"] [unique_id "CONTOH_UNIQUE_ID"]ARGS:pesan). Ketiga, potongan data yang cocok dengan pola. Bagian terakhir ini yang menentukan apakah ini false positive.
Untuk memastikannya, baca isi yang cocok itu dengan akal sehat. Kalau isinya kalimat wajar dari pelanggan, misalnya pertanyaan yang kebetulan mengandung kata-kata mirip SQL, itu false positive. Kalau isinya payload aneh dari IP yang juga mencoba path lain seperti wp-login.php atau file konfigurasi, itu mungkin serangan sungguhan dan rule bekerja sebagaimana mestinya. Cek juga apakah pola blokir yang sama muncul dari banyak IP berbeda yang semuanya mengirim pesan normal. Itu tanda kuat rule-nya terlalu ketat untuk form tersebut.
Satu catatan keamanan. Audit log bisa berisi isi form lengkap: nama, email, nomor telepon, isi pesan. Batasi siapa yang bisa membacanya, dan jangan menempelkan potongan mentahnya ke tiket atau chat. Cukup kutip rule ID, nama parameter, dan unique_id.
Mitigasi sementara: lepas satu rule hanya di path form
SecRuleRemoveById di dalam blok LocationMatch yang cocok dengan path form. Panel seperti WHM juga punya menu untuk melihat hit ModSecurity dan menonaktifkan rule. Periksa dulu apakah cakupannya global untuk semua akun atau per domain, karena menonaktifkan rule secara global demi satu form berarti melonggarkan semua situs di server itu.
Setelah perubahan apa pun, jalankan apachectl configtest (atau padanannya di web server kamu) sebelum reload. Lalu minta pelanggan mencoba lagi dengan isi pesan yang sama persis. Kalau berhasil dan tidak ada baris Warning baru dari rule itu, mitigasinya bekerja.
Perbaikan permanen: exclusion sempit yang tahan update
ctl:ruleRemoveTargetById untuk keperluan ini:
APACHE
# Muat SEBELUM file rule CRS. ID 1000100 hanya contoh; pakai ID lokal yang belum terpakai.
# Untuk request ke /kontak/, rule 942100 berhenti memeriksa parameter 'pesan' saja.
SecRule REQUEST_FILENAME "@beginsWith /kontak/" \
"id:1000100,phase:1,pass,nolog,ctl:ruleRemoveTargetById=942100;ARGS:pesan"ctl di fase awal harus dievaluasi sebelum rule CRS berjalan, jadi exclusion seperti ini biasanya ditaruh di file yang di-include sebelum CRS. Ketiga, simpan di file custom milikmu sendiri, bukan di file rule bawaan. File bawaan bisa tertimpa saat rule set diperbarui, dan perbaikanmu akan hilang tanpa ada yang sadar.
Di server dengan control panel, lokasi file custom dan cara memuatnya tergantung panel dan versinya. Cek dokumentasinya supaya perubahan tidak hilang saat panel membangun ulang konfigurasi web server.
Terakhir, catat exclusion ini di dokumentasi atau komentar file: rule ID, path, parameter, alasan, dan unique_id contoh yang jadi dasarnya. Beberapa bulan kemudian, ketika ada yang bertanya kenapa rule itu dikecualikan, jawabannya sudah ada dan tidak perlu diselidiki ulang.
Jadi, setiap ada laporan 403 di form, ambil unique_id dari baris 949110, cari baris Warning dengan ID yang sama, lalu baca Matched Data untuk memutuskan apakah itu false positive. Kalau memang false positive, buat exclusion sesempit mungkin dan simpan di tempat yang tidak tertimpa update. WAF tetap menyala, dan form pelanggan kembali bisa dipakai.