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, atauwindow.name. - Sink: Fungsi atau objek DOM yang dapat mengeksekusi kode atau merender HTML jika diberikan data yang tidak aman, seperti
document.write(),element.innerHTML, ataueval().
| 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 propertitextContentatauinnerTextuntuk 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.