DOM-Based XSS Tutorial: Analisis, Eksploitasi, dan Mitigasi

DOM-Based Cross-Site Scripting (XSS) adalah kerentanan keamanan aplikasi web di mana skrip berbahaya (biasanya JavaScript) dieksekusi akibat manipulasi Document Object Model (DOM) di sisi klien. Berbeda dengan Stored atau Reflected XSS yang melibatkan interaksi server, DOM XSS terjadi sepenuhnya di dalam browser korban ketika skrip yang sah memproses data dari sumber yang tidak tepercaya (source) dan memasukkannya ke dalam eksekutor berbahaya (sink).

Pemahaman mendalam mengenai alur data dari source ke sink menjadi kunci utama dalam melakukan audit keamanan maupun pengkodean aplikasi web yang aman. Berikut adalah penjabaran teknis mengenai komponen, skenario kerentanan, serta cara pencegahannya.

Anatomi DOM-Based XSS: Source dan Sink

Kerentanan DOM XSS selalu melibatkan dua elemen utama: objek Source (titik masuk data yang dikontrol pengguna) dan objek Sink (fungsi atau elemen DOM yang mengeksekusi kode atau merender HTML secara tidak aman).

Tipe Komponen Nama Objek / Properti Deskripsi Teknis
Source location.search Mengambil parameter query string dari URL.
Source location.hash Mengambil fragment identifier dari URL (setelah tanda #).
Source document.referrer Mengambil URL halaman sebelumnya.
Sink element.innerHTML Menyisipkan string mentah sebagai elemen HTML ke DOM.
Sink eval() Mengeksekusi string apa pun sebagai kode JavaScript.
Sink document.write() Menulis string langsung ke aliran dokumen (document stream).

Contoh Kode Rentan (Vulnerable Code)

Berikut adalah contoh implementasi JavaScript sisi klien yang rentan terhadap DOM-based XSS karena langsung memasukkan nilai dari location.search ke dalam sink innerHTML tanpa sanitasi.

<!-- Halaman HTML Rentan: index.html -->
<div id="greeting"></div>

<script>
  // Mengambil parameter 'name' dari URL query string
  const urlParams = new URLSearchParams(window.location.search);
  const userName = urlParams.get('name');

  // Sink berbahaya: menggunakan innerHTML dengan data tanpa sanitasi
  if (userName) {
    document.getElementById('greeting').innerHTML = "<h1>Halo, " + userName + "</h1>";
  }
</script>

Contoh Payload Eksploitasi

Jika pengguna mengakses URL berikut, skrip berbahaya akan dieksekusi di dalam konteks browser korban:

https://example.com/index.html?name=<img+src=x+onerror=alert(document.domain)>

Langkah Mitigasi dan Penanggulangan

Untuk mencegah DOM-based XSS, pengembang harus menghindari penggunaan sink yang berbahaya atau memastikan data dari source telah dibersihkan (sanitasi) dengan benar sebelum dimasukkan ke dalam DOM.

  1. Gunakan Properti Aman: Ganti penggunaan innerHTML dengan textContent atau innerText jika hanya ingin menyisipkan teks biasa, bukan elemen HTML.
  2. Implementasikan Context-Aware Encoding: Jika elemen HTML wajib dirender dari input pengguna, gunakan pustaka sanitasi pihak ketiga yang teruji seperti DOMPurify sebelum memasukkannya ke sink.
  3. Terapkan Content Security Policy (CSP): Batasi sumber eksekusi skrip dengan header CSP yang ketat untuk mencegah eksekusi skrip inline yang tidak sah.

Contoh penggunaan textContent yang aman:

// Aman dari DOM XSS
document.getElementById('greeting').textContent = "Halo, " + userName;