Review Pencegahan XSS: Encoding Berdasarkan Konteks
Pencegahan XSS bergantung pada konteks output. Teks HTML, atribut ber-quote, URL, string JavaScript, dan CSS memerlukan encoding berbeda; satu fungsi escaping tidak dapat menutup semuanya dengan aman.
Review sink, bukan label
Telusuri nilai tidak tepercaya sampai sink DOM atau template server. Contoh: nama tampilan aman pada teks HTML setelah HTML encoding, tetapi tidak aman bila dimasukkan ke onclick. Contoh lain: return URL membutuhkan validasi scheme sebelum URL encoding.
Tabel konteks-ke-encoding
| Sink | Kontrol | Uji negatif |
|---|---|---|
| teks HTML | HTML encoder | tag tampil sebagai teks |
| atribut | attribute encoder dan quote | quote tidak dapat keluar |
| URL | scheme allowlist | javascript: ditolak |
| rich text | sanitizer terpelihara | event handler dihapus |
Panduan pencegahan XSS OWASP dan CWE-79 menjelaskan perbedaan ini.
Aturan keputusan: jangan mengirim string tidak tepercaya ke DOM sink berbahaya tanpa kontrol sesuai konteks.
Remediasi
Utamakan auto-escaping framework, hapus sink berbahaya, sanitasi rich text, dan tambahkan regression payload untuk tiap konteks. CSP membantu membatasi dampak tetapi tidak memperbaiki encoding salah. Audit kode dapat mengikuti jalur template dan klien.
Review rendering, bukan hanya input
Inventarisasi setiap interpolasi template, sink sisi klien, batas rich text, pembuat URL, dan escape hatch framework. Biarkan template melakukan encoding untuk teks HTML biasa. Gunakan atribut tetap yang diberi quote dan hindari nilai tidak tepercaya dalam event handler, script mentah, selector, atau konstruksi markup. Untuk link, validasi scheme dan kebijakan host yang diizinkan sebelum meng-encode komponen lalu meng-encode konteks atribut. Gunakan textContent alih-alih parsing HTML bila yang dimaksud teks.
Uji satu payload untuk tiap konteks bernama dan simpan output render, bukan hanya source code. Masukkan quote escape, teks tag, URL javascript, event inline, JSON breaker, dan regresi sanitizer. Owner: pemilik frontend. Lulus: konten tampil sebagai data dan tidak ada script berjalan. Gagal: nilai tidak tepercaya mengubah struktur DOM, scheme URL, atau perilaku script. Pengecualian wajib mengidentifikasi sink, pembatasan sementara, CSP atau isolasi kompensasi, pemilik risiko, tugas remediasi, dan kedaluwarsa.
Artefak per sink
Simpan tabel berisi route atau komponen, sumber nilai, sink tepat, konteks, transformasi wajib, dan payload negatif. Nama pelanggan pada teks HTML memakai template escaping; tujuan outbound mendapat validasi scheme, encoding komponen, lalu encoding atribut ber-quote. Peta ini memperlihatkan raw rendering escape hatch yang muncul pada perubahan framework berikutnya.
Jejak konteks rendering
Output yang diharapkan: field sumber, komponen, API sink, kelas konteks, versi encoder atau sanitizer, ID payload, hasil DOM render. Bukti ini menghubungkan konteks sink dengan hasil DOM yang tercatat.
Kegagalan teruji: Nama tampilan berisi markup mencapai text node dan harus merender karakter, bukan elemen. Field URL harus gagal validasi scheme sebelum encoding atribut.
Kasus tepi: Sanitasi rich text tidak aman setelah konkatenasi di hilir. Jaga output tersanitasi tetap tidak berubah atau sanitasi ulang setelah transformasi disengaja.
Uji penutupan: Jalankan payload regresi browser terhadap tiap sink terpetakan. Penutupan lulus bila DOM hanya berisi data dan tidak ada event handler atau script berjalan.
Latihan inventory konteks
Telusuri nilai dari parameter request, field database, dokumen impor, fragmen URL, dan browser storage ke lokasi rendering akhirnya. Klasifikasikan setiap penggunaan sebagai text node, atribut ber-quote, komponen URL, data JSON, nilai style, atau rich HTML yang disetujui. Nilai tanpa konteks diketahui adalah temuan review, bukan kandidat escaping generik. Helper framework perlu diuji pada escape hatch-nya, termasuk properti HTML mentah dan fungsi template klien.
Fixture browser dapat mengatur nama tampilan menjadi markup, URL gambar menjadi scheme terlarang, dan komentar menjadi kandidat bypass sanitizer. Output yang diharapkan adalah teks encoded yang terlihat, URL ditolak, dan markup tidak aman dihapus. Review source map atau bundled code untuk sink yang muncul setelah kompilasi. Jika produk memerlukan HTML, definisikan elemen dan atribut yang diizinkan sebagai kebijakan konten; jangan menganggap nama library sanitizer sebagai bukti cukup.
Fixture penutupan harus menjalankan rendering server dan klien terhadap nilai sama. Output yang diharapkan berbeda menurut konteks tetapi tetap inert di semua tempat. Review harus gagal bila kode mengubah teks encoded kembali menjadi markup sebelum browser menerimanya.
Review DOM harus mencakup nilai yang dirakit setelah halaman awal dimuat. Telusuri event listener, parameter client router, handler postMessage, dan pembacaan storage untuk data tidak tepercaya yang mencapai API mampu HTML. Halaman server-rendered dapat aman sementara update klien berikutnya menambah DOM XSS. Gunakan test yang mengubah state route setelah load lalu periksa DOM hasilnya. Dokumentasikan apakah Trusted Types tersedia sebagai kontrol tambahan, tetapi jangan menganggap browser tidak didukung telah tercakup.
Pemeriksaan akhir memasangkan setiap sink rendering dengan encoder konteks dan hasil fixture berbahaya. Output diharapkan: data ditampilkan sebagai data tanpa eksekusi script atau perubahan DOM tidak diharapkan. Kasus tepi: template pihak ketiga menggabungkan atribut dan URL; uji konteks hasil akhirnya. Tutup hanya setelah rendering terdeploy dan update klien sama-sama tetap inert.