Mitigasi DOM-Based XSS: Panduan & Contoh Kode Aman

Definisi dan Cara Kerja DOM-Based XSS

DOM-Based XSS terjadi ketika aplikasi web memuat data dari sumber yang tidak tepercaya (source) melalui JavaScript, lalu mengeksekusinya ke dalam Document Object Model (sink) tanpa sanitasi yang memadai. Eksekusi skrip terjadi sepenuhnya di sisi klien (browser) tanpa melibatkan server dalam proses pemantulan (reflection) atau penyimpanan (storage) payload.

Komponen utama dalam celah keamanan ini terbagi menjadi dua: Source (seperti location.search, location.hash, document.referrer) dan Sink (seperti element.innerHTML, document.write(), fungsi eval()). Jika input dari Source langsung dimasukkan ke Sink tanpa validasi, browser akan mengeksekusi payload berbahaya tersebut sebagai kode JavaScript aktif.

Tabel Matriks Sink Berisiko dan Solusi Aman

Pengembang harus mengenali sink berbahaya dan menggantinya dengan metode manipulasi DOM yang aman untuk mencegah eksekusi skrip sembarangan.

Sink Berisiko Tinggi Risiko Keamanan Alternatif Aman
element.innerHTML Mengeksekusi tag HTML dan skrip inline. Gunakan element.textContent atau element.innerText.
document.write() Menulis string mentah langsung ke dokumen. Hindari penggunaannya; gunakan manipulasi node DOM standar.
eval() / setTimeout() Mengeksekusi string sebagai kode logika. Gunakan fungsi callback atau JSON.parse() untuk data.
element.outerHTML Mengganti elemen luar dengan HTML mentah. Gunakan document.createElement() dan appendChild().

Penerapan Kode Mitigasi Teknis

Berikut adalah perbandingan penulisan kode yang rentan terhadap DOM-Based XSS dan cara memperbaikinya menggunakan fungsi bawaan JavaScript yang aman.

// CONTOH RENTAN (Vulnerable Code)
const userInput = new URLSearchParams(window.location.search).get('name');
// Penyerang dapat mengirim payload <img src=x onerror=alert(1)>
document.getElementById('greeting').innerHTML = 'Halo, ' + userInput;

// CONTOH AMAN (Mitigated Code)
const safeInput = new URLSearchParams(window.location.search).get('name');
const greetingEl = document.getElementById('greeting');
// Menggunakan textContent mengonversi string menjadi teks biasa, bukan HTML
greetingEl.textContent = 'Halo, ' + safeInput;

Strategi Pertahanan Berlapis (Defense-in-Depth)

Mengandalkan satu lapisan pertahanan saja tidak cukup untuk mengamankan aplikasi web modern dari serangan injeksi berbasis DOM. Kombinasikan beberapa mekanisme keamanan berikut:

  • Content Security Policy (CSP): Terapkan header CSP yang ketat untuk melarang eksekusi skrip inline (unsafe-inline) dan membatasi sumber skrip eksternal yang diizinkan memuat kode.
  • Context-Aware Encoding: Lakukan encoding karakter khusus (seperti < menjadi &lt;) sebelum merender data ke dalam konteks HTML, atribut, atau JavaScript.
  • Penggunaan Library Pihak Ketiga yang Aman: Jika aplikasi benar-benar membutuhkan rendering HTML dinamis, gunakan pustaka sanitasi terpercaya seperti DOMPurify sebelum memasukkannya ke dalam sink.
  • Analisis Kode Otomatis: Integrasikan pemindai Static Application Security Testing (SAST) pada pipeline CI/CD untuk mendeteksi penggunaan sink berbahaya secara dini.

Troubleshooting Kerentanan DOM XSS di Lapangan

Gunakan langkah-langkah berikut saat melakukan audit atau memperbaiki temuan celah keamanan DOM-Based XSS pada aplikasi produksi:

  1. Lacak aliran data (data flow analysis) dari objek location atau window menggunakan fitur Debugger browser untuk melihat titik akhir (sink) eksekusi.
  2. Periksa apakah ada penggunaan fungsi jQuery( atau metode html() yang menerima parameter dari URL secara langsung.
  3. Ganti semua kemunculan manipulasi DOM berbasis string mentah dengan metode berbasis Node API murni.
  4. Uji ulang dengan payload standar injeksi XSS untuk memastikan browser memperlakukan input sebagai string teks murni.