Sebuah kolom komentar, nama pengguna, judul artikel, atau parameter URL terlihat seperti data biasa. Namun begitu data itu ditampilkan kembali ke browser tanpa perlindungan yang tepat, ia bisa berubah menjadi pintu masuk cross-site scripting atau XSS.
XSS terjadi ketika browser memperlakukan data yang seharusnya hanya menjadi teks sebagai HTML atau JavaScript. Dampaknya tidak selalu berupa halaman yang berubah tampilan. Dalam kondisi tertentu, penyerang dapat menyalahgunakan sesi pengguna, menampilkan formulir palsu, memantau interaksi, atau menjalankan tindakan atas nama korban. OWASP mengingatkan bahwa XSS bukan satu masalah dengan satu obat; pertahanan harus disesuaikan dengan tempat data tersebut digunakan.
Kesalahan yang sering terjadi: menganggap semua data aman
Banyak aplikasi menerima data melalui formulir, URL, cookie, API, atau database. Pengembang kemudian merasa aman karena sudah memeriksa input saat data masuk. Padahal, data yang lolos validasi tetap perlu diamankan lagi ketika ditampilkan.
Bayangkan seseorang mengisi nama dengan teks biasa. Nilainya mungkin aman saat disimpan di database, tetapi konteksnya berubah ketika nama itu dimasukkan ke dalam atribut HTML, URL, atau kode JavaScript. Browser membaca setiap konteks dengan aturan yang berbeda. Karena itu, satu fungsi escape tidak cocok untuk semua tempat.
Validasi input menjawab pertanyaan: “Apakah data ini sesuai aturan aplikasi?” Escaping menjawab pertanyaan: “Bagaimana data ini ditampilkan sebagai data, bukan sebagai kode?” Sanitasi digunakan ketika aplikasi memang perlu menerima sebagian HTML, misalnya editor artikel atau komentar dengan format tertentu.
Prinsip utama: amankan data saat akan ditampilkan
Untuk teks biasa di dalam HTML, gunakan output escaping. Proses ini mengubah karakter khusus seperti tanda lebih kecil atau tanda kutip menjadi bentuk yang tidak ditafsirkan sebagai markup.
Dalam PHP, fungsi dasar yang umum dipakai adalah htmlspecialchars(). Contohnya:
<?php
$name = $_GET['name'] ?? '';
echo htmlspecialchars($name, ENT_QUOTES, 'UTF-8');ENT_QUOTES membantu mengubah tanda kutip tunggal dan ganda, sementara deklarasi UTF-8 membuat penanganan karakter lebih jelas. Namun, fungsi ini cocok untuk konteks teks HTML dan atribut sederhana, bukan untuk semua tempat.
Jangan menaruh data pengguna langsung ke dalam blok JavaScript, CSS, event handler seperti onclick, atau URL hanya karena sudah melewati htmlspecialchars(). OWASP menekankan bahwa encoding harus mengikuti konteks tujuan. HTML encoding tidak otomatis membuat nilai aman untuk JavaScript atau URL.
Pola aman di WordPress
WordPress sudah menyediakan fungsi escaping yang sebaiknya dipakai ketika output dibuat. Prinsipnya sederhana: lakukan escaping sedekat mungkin dengan saat data dicetak, bukan hanya ketika data disimpan.
esc_html()untuk teks yang ditampilkan di antara tag HTML.esc_attr()untuk nilai atribut seperticlass,title, atauvalue.esc_url()untuk URL yang dipakai pada atribut sepertihrefdansrc.wp_kses()atauwp_kses_post()ketika aplikasi memang perlu mempertahankan HTML yang diizinkan.
Contoh yang lebih aman untuk judul dan tautan:
<h2><?php echo esc_html( $title ); ?></h2>
<a href="<?php echo esc_url( $url ); ?>">
<?php echo esc_html( $label ); ?>
</a>Hindari pola seperti echo $title; jika nilainya berasal dari pengguna, metadata, API, atau sumber lain yang belum benar-benar Anda kendalikan. Database internal juga bukan alasan untuk menganggap data selalu bersih. Data bisa saja masuk melalui impor, plugin lain, akun admin yang diretas, atau proses lama yang memiliki celah.
Escaping bukan berarti menghapus semua HTML
Kesalahan lain adalah memakai satu pendekatan untuk seluruh konten. Jika pengguna hanya boleh memasukkan nama, gunakan validasi ketat dan tampilkan sebagai teks. Jika pengguna boleh menulis artikel dengan format tebal, tautan, dan daftar, menghapus semua HTML akan merusak fungsi yang memang diinginkan.
Dalam situasi tersebut, gunakan sanitasi dengan daftar elemen dan atribut yang diperbolehkan. Di WordPress, wp_kses_post() dapat membantu mempertahankan subset HTML yang lazim digunakan dalam konten, tetapi tetap perlu memperhatikan kebutuhan aplikasi dan pembaruan keamanan.
Sanitasi juga bukan proses sekali seumur hidup. Pustaka sanitasi harus diperbarui, dan hasil yang sudah disanitasi jangan dimodifikasi lagi dengan cara yang dapat memasukkan kembali konten berbahaya.
Periksa juga XSS yang terjadi di browser
XSS tidak selalu berasal dari template PHP. Kode JavaScript di browser juga dapat membuat masalah, terutama saat mengambil nilai dari URL, location.hash, atau input pengguna lalu memasukkannya ke innerHTML.
Untuk menampilkan teks biasa melalui JavaScript, lebih aman memakai textContent:
const message = new URLSearchParams(location.search).get('message') || '';
document.querySelector('#message').textContent = message;Berhati-hatilah dengan innerHTML, document.write(), eval(), dan atribut event handler. Jika aplikasi benar-benar perlu merender HTML dari pengguna, gunakan sanitizer yang dirawat dan dikonfigurasi dengan benar, bukan sekadar menghapus kata <script>.
Yang bisa dilakukan sekarang
- Daftar semua tempat aplikasi menampilkan data dari pengguna: halaman HTML, atribut, URL, JavaScript, email, dan respons API.
- Pasangkan fungsi escaping dengan konteksnya, bukan dengan asal datanya saja.
- Di WordPress, ganti output langsung seperti
echo $valuedengan fungsi yang sesuai, misalnyaesc_html()atauesc_attr(). - Cari penggunaan
innerHTML,document.write(), dan event handler inline di JavaScript. - Tambahkan pengujian untuk karakter seperti
<,>, tanda kutip, dan nilai yang menyerupai URL atau HTML. - Gunakan Content Security Policy sebagai lapisan tambahan, bukan sebagai pengganti perbaikan kode.
Intinya, data pengguna tidak harus dianggap sebagai musuh dan tidak selalu perlu dibuang. Yang penting adalah menjaga agar browser memahami data tersebut sebagai data. Validasi membatasi apa yang boleh masuk, sanitasi membersihkan HTML ketika HTML memang diperlukan, sedangkan escaping memastikan data tidak berubah menjadi kode saat ditampilkan.
Sumber & bacaan lebih lanjut
- OWASP Cross Site Scripting Prevention Cheat Sheet
- WordPress Developer Resources: Escaping Data
- PHP Manual: htmlspecialchars
– Rio Yotto @rioyotto
