Lewati ke isi

Keamanan/Cyber Security

Apa Itu XSS dan Contoh Serangannya di Formulir Website

XSS membuat skrip penyerang berjalan di browser pengunjung atau admin. Lihat contohnya di formulir kontak, komentar, dan pencarian, serta cara menutupnya.

Terbit 5 menit baca

Jawaban singkat

XSS (cross-site scripting) adalah celah saat input pengunjung ditampilkan ulang tanpa di-encode sehingga browser menjalankannya sebagai skrip. Formulir kontak, komentar, dan pencarian adalah pintu masuk yang umum. Cegah dengan output encoding sesuai konteks, sanitasi HTML, CSP, dan cookie HttpOnly.

Daftar isi
  1. Apa itu XSS sebenarnya?
  2. Tiga bentuk XSS dan contohnya di formulir
  3. Encoding sesuai konteks adalah kuncinya
  4. Lapisan tambahan yang memperkecil dampak
  5. Memeriksa website sendiri

Suatu pagi kamu membuka dashboard admin untuk membaca pesan yang masuk dari formulir kontak. Isinya tampak biasa, mungkin hanya satu kalimat pertanyaan harga. Tapi di balik layar, pesan itu membawa potongan kode yang langsung berjalan di browsermu, dengan hak akses admin yang sedang login. Kamu tidak mengklik apa pun. Cukup membuka halaman.

Itulah gambaran XSS, atau cross-site scripting. Celahnya bukan di formulir itu sendiri, melainkan di tempat isi formulir ditampilkan kembali. Kalau aplikasi menampilkan teks dari pengunjung tanpa mengubah karakter khusus seperti < dan >, browser akan menganggap teks itu bagian dari halaman, termasuk tag <script> di dalamnya.

Apa itu XSS sebenarnya?

XSS adalah celah yang memungkinkan penyerang menyisipkan skrip ke halaman website yang kemudian dijalankan di browser orang lain. Karena skrip itu berjalan dari domain websitemu, browser memperlakukannya sebagai skrip sah. Ia bisa membaca isi halaman, mengirim permintaan atas nama pengguna yang sedang login, mengubah tampilan, atau mengalihkan pengunjung ke situs lain. Bila cookie sesi tidak dilindungi, skrip juga bisa mencurinya, yang berujung pada session hijacking.

Dalam OWASP Top 10 edisi 2025, XSS dikelompokkan dalam kategori Injection, sama seperti SQL injection. Bedanya, SQL injection menyerang database di server, sedangkan XSS menyerang browser pengguna.

Tiga bentuk XSS dan contohnya di formulir

Contoh payload di bawah sengaja memakai alert(1), cara standar penguji keamanan untuk membuktikan celah tanpa merusak apa pun. Penyerang sungguhan memakai skrip yang jauh lebih diam.

JenisContoh di formulirSiapa yang terkenaKapan berjalan
Stored (tersimpan)Kolom pesan formulir kontak diisi <script>alert(1)</script>, lalu ditampilkan di dashboard adminAdmin atau semua pengunjung halamanSetiap kali data itu ditampilkan
Reflected (dipantulkan)Halaman pencarian menulis "Hasil untuk: ..." langsung dari parameter ?q=Orang yang membuka tautan buatan penyerangSaat tautan dibuka
DOM-basedJavaScript halaman mengambil nilai dari URL atau kolom input lalu memasukkannya lewat innerHTMLOrang yang membuka tautan atau halaman tertentuSepenuhnya di browser, server tidak melihatnya

Stored XSS paling berbahaya untuk website bisnis karena sasarannya sering admin. Formulir kontak, ulasan produk, kolom nama di checkout, dan tiket bantuan semuanya menyimpan input pengunjung lalu menampilkannya di panel admin. Bila panel itu lupa melakukan encoding, satu pesan bisa memberi penyerang akses setara admin selama sesi berlangsung, misalnya untuk membuat akun admin baru lewat permintaan yang dikirim diam-diam.

Reflected XSS biasanya disebar lewat tautan. Contohnya tautan ke halaman pencarianmu yang parameternya berisi skrip, dikirim lewat email atau chat. Karena domainnya asli milikmu, korban tidak curiga.

DOM-based XSS makin sering muncul seiring banyaknya JavaScript di sisi depan. Kode seperti elemen.innerHTML = nilaiDariUrl cukup untuk membuka celah, dan karena prosesnya terjadi di browser, log server tidak mencatat apa-apa.

Encoding sesuai konteks adalah kuncinya

Aturan paling penting: setiap data dari luar harus di-encode tepat saat ditampilkan, sesuai tempat ia muncul. Teks di dalam isi HTML, di dalam atribut, di dalam JavaScript, dan di dalam URL punya aturan encoding yang berbeda. Lembar panduan pencegahan XSS dari OWASP menjelaskan perbedaan konteks ini dengan rinci.

Di PHP murni, untuk teks yang ditampilkan di HTML, gunakan:

echo htmlspecialchars($pesan, ENT_QUOTES, 'UTF-8');

Fungsi ini mengubah <, >, &, dan tanda kutip menjadi entitas HTML, sehingga browser menampilkannya sebagai teks biasa. Di WordPress, pakai fungsi escaping bawaan sesuai konteks: esc_html() untuk isi teks, esc_attr() untuk atribut, esc_url() untuk tautan, dan wp_kses() bila kamu memang ingin mengizinkan sebagian tag HTML. Kebanyakan mesin template modern seperti Twig, Blade, dan Jinja juga melakukan escaping secara otomatis, selama kamu tidak mematikannya dengan filter "raw" atau sejenisnya.

Untuk kolom yang memang boleh berisi HTML, seperti editor artikel atau deskripsi produk, jangan menyaring sendiri dengan mencari kata script. Penyerang punya banyak cara lain, misalnya atribut onerror pada gambar. Gunakan pustaka sanitasi yang sudah teruji dengan daftar tag dan atribut yang diizinkan.

Di sisi JavaScript, isi teks dengan textContent, bukan innerHTML. Perbedaan kecil ini menutup sebagian besar celah DOM-based XSS.

Lapisan tambahan yang memperkecil dampak

Encoding adalah pertahanan utama, tapi beberapa lapisan lain membuat satu kesalahan kecil tidak langsung menjadi bencana.

Content Security Policy (CSP) adalah header yang memberi tahu browser dari mana saja skrip boleh dimuat. CSP yang ketat, misalnya hanya mengizinkan skrip dari domain sendiri dan melarang skrip inline, membuat skrip yang disisipkan penyerang ditolak browser. Penerapannya perlu diuji bertahap karena bisa mematikan skrip pihak ketiga seperti analytics atau chat, dan mode Content-Security-Policy-Report-Only berguna untuk mencoba tanpa memblokir.

Cookie sesi dengan atribut HttpOnly tidak bisa dibaca JavaScript, sehingga XSS tidak bisa mencurinya secara langsung. Skrip penyerang masih bisa beraksi di halaman, tapi tidak bisa membawa pulang kunci sesi.

Validasi input tetap berguna sebagai saringan awal. Kolom nomor telepon cukup menerima angka, tanda plus, dan spasi. Kolom email harus berformat email. Validasi seperti ini tidak menggantikan encoding, tapi mempersempit ruang gerak penyerang.

Terakhir, perlindungan formulir dari serangan lain seperti CSRF sebaiknya dipasang bersamaan, karena XSS dan CSRF sering dibahas dan diuji berdampingan. Penjelasannya ada di apa itu CSRF dan token formulir.

Memeriksa website sendiri

Cara paling sederhana untuk mulai: isi setiap formulir di website milikmu dengan teks seperti <b>uji</b> atau "><i>uji</i>, lalu lihat di mana teks itu ditampilkan, termasuk di panel admin dan email notifikasi. Kalau yang muncul adalah huruf tebal atau miring, bukan teks apa adanya, berarti ada bagian yang tidak di-encode dan perlu diperiksa programmer. Lakukan hanya di website milikmu sendiri, lebih baik di salinan staging.

Untuk situs berbasis CMS, sebagian besar celah XSS datang dari plugin dan tema. Pembaruan rutin dan membuang plugin yang ditinggalkan pembuatnya menutup banyak celah sebelum sempat dipakai.

XSS terjadi karena satu hal sederhana: teks dari pengunjung diperlakukan sebagai kode. Encode setiap data saat ditampilkan, sanitasi HTML dengan pustaka teruji, lalu tambahkan CSP dan cookie HttpOnly sebagai jaring pengaman. Mulailah dari halaman yang dibaca admin, karena di sanalah satu celah kecil paling mahal akibatnya.

Sumber & referensi

Baca juga