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.
- Gunakan Properti Aman: Ganti penggunaan
innerHTMLdengantextContentatauinnerTextjika hanya ingin menyisipkan teks biasa, bukan elemen HTML. - 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.
- 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;