Dom Based XSS Example: Cara Kerja dan Contoh Kasus

DOM-Based Cross-Site Scripting (XSS) adalah kerentanan keamanan aplikasi web di mana kode berbahaya (payload) dieksekusi sebagai hasil dari modifikasi DOM (Document Object Model) di lingkungan browser korban. Tidak seperti Reflected atau Stored XSS yang melibatkan interaksi server, DOM-Based XSS sepenuhnya terjadi pada sisi klien (client-side), di mana skrip yang rentan membaca data dari sumber yang dapat dimanipulasi (source) dan mengirimkannya ke fungsi berbahaya (sink).

Kerentanan ini muncul ketika pengembang menggunakan data masukan dari pengguna secara langsung tanpa melakukan validasi atau sanitasi terlebih dahulu sebelum memasukkannya kembali ke elemen DOM. Pemahaman mendalam mengenai source, sink, dan implementasi kode nyata sangat krusial untuk mencegah eksploitasi celah keamanan ini pada aplikasi web modern.

Mekanisme Dasar DOM-Based XSS

Dalam arsitektur DOM-Based XSS, terdapat dua komponen utama yang saling berinteraksi: Source dan Sink.

  • Source: Properti JavaScript yang dapat dikendalikan oleh penyerang, seperti location.search, location.hash, document.referrer, atau window.name.
  • Sink: Fungsi atau objek DOM yang dapat mengeksekusi kode atau merender HTML jika diberikan data yang tidak aman, seperti document.write(), element.innerHTML, atau eval().
Komponen Nama Objek/Properti Deskripsi Risiko
Source Umum location.search Mengambil parameter query string dari URL yang dapat diubah oleh pengguna.
Source Umum location.hash Mengambil fragment identifier (#) dari URL.
Sink Berbahaya element.innerHTML Menyisipkan string HTML mentah ke dalam elemen DOM, memicu eksekusi skrip.
Sink Berbahaya document.write() Menulis string teks langsung ke alur dokumen HTML.

Contoh Kode Rentan (Vulnerable Code Example)

Berikut adalah contoh implementasi skrip JavaScript yang rentan terhadap DOM-Based XSS menggunakan properti location.search sebagai source dan innerHTML sebagai sink.

<!-- Halaman HTML yang Rentan -->
<div id="welcome-message"></div>

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

  // Sink berbahaya: Memasukkan input mentah langsung ke DOM
  if (userName) {
    document.getElementById('welcome-message').innerHTML = 'Halo, ' + userName;
  }
</script>

Analisis Eksploitasi

Jika pengguna mengakses URL berikut pada aplikasi di atas:

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

Skrip akan membaca string tag <img> melalui URLSearchParams dan memasukkannya ke dalam elemen #welcome-message melalui innerHTML. Browser akan mencoba memuat gambar dengan sumber yang tidak ada, memicu event onerror, dan mengeksekusi fungsi JavaScript alert(document.cookie).

Cara Mitigasi dan Pencegahan

Untuk mengamankan aplikasi dari kerentanan DOM-Based XSS, pengembang harus menerapkan prinsip penanganan data yang aman pada sisi klien:

  • Gunakan Text Content: Alih-alih menggunakan innerHTML, gunakan properti textContent atau innerText untuk memasukkan teks biasa ke dalam elemen DOM. Properti ini secara otomatis melakukan enkode karakter khusus HTML.
  • Validasi dan Sanitasi Input: Lakukan validasi ketat terhadap format data yang diterima dari source (menggunakan whitelist regex). Jika merender HTML tidak dapat dihindari, gunakan pustaka sanitasi pihak ketiga yang teruji seperti DOMPurify.
  • Terapkan Content Security Policy (CSP): Header CSP yang ketat dapat membatasi eksekusi skrip inline dan mencegah pemuatan sumber daya eksternal yang tidak sah.
<!-- Perbaikan Menggunakan textContent -->
<div id="welcome-message"></div>

<script>
  const urlParams = new URLSearchParams(window.location.search);
  const userName = urlParams.get('name');

  // Aman: textContent memperlakukan input sebagai teks murni, bukan HTML
  if (userName) {
    document.getElementById('welcome-message').textContent = 'Halo, ' + userName;
  }
</script>

Kesimpulan Teknis

DOM-Based XSS terjadi sepenuhnya di dalam browser klien tanpa melibatkan respons server secara langsung. Dengan memahami hubungan antara sumber data (source) dan titik eksekusi (sink), serta mengganti fungsi manipulasi DOM yang tidak aman dengan alternatif seperti textContent, risiko eksploitasi celah keamanan ini dapat diminimalisasi secara efektif.