setHTML() berguna ketika aplikasi perlu menampilkan HTML dari masukan yang tidak tepercaya. Metode ini menyaring elemen dan atribut berbahaya sebelum memasukkan hasil ke DOM. Namun, penggantian innerHTML bukan pemeriksaan keamanan menyeluruh. Panduan ini menunjukkan cara memeriksa dukungan API, menguji satu masukan berbahaya, dan mempertahankan tampilan teks ketika API tidak tersedia.
Pilih teks biasa atau HTML terlebih dahulu
Penggunaan textContent dan Pemeriksaan Fitur
Untuk judul, nama pengguna, atau komentar yang tidak membutuhkan format HTML, gunakan textContent. Tanda kurung siku akan ditampilkan sebagai teks, bukan diproses sebagai markup. Jika format seperti paragraf dan huruf tebal memang dibutuhkan, periksa apakah elemen tujuan memiliki metode setHTML. Jangan mengganti jalur yang tidak didukung dengan innerHTML untuk masukan tidak tepercaya.
Uji yang dapat dijalankan sendiri
Jalankan contoh berikut di konsol pengembang pada halaman kosong milik sendiri. Contoh membuat dokumen terpisah dan tidak memasang masukan uji ke halaman aktif. Jangan menjalankan kode dari sumber yang tidak dipahami pada halaman akun atau layanan sensitif. Masukan sengaja memuat skrip, atribut kejadian, dan URL berbahaya agar hasil sanitasi dapat diperiksa.
(() => {
const input = '<p>Halo <strong>pembaca</strong></p>'
+ '<img src="x" onclick="alert(1)">'
+ '<script>alert(1)</script>'
+ '<a href="javascript:alert(1)">tautan</a>';
function renderHtml(target, html) {
if (typeof target.setHTML === 'function') {
target.setHTML(html);
} else {
target.textContent = html;
}
}
// Dokumen terpisah; contoh tidak dipasang ke halaman aktif.
const doc = document.implementation.createHTMLDocument('Uji sanitasi');
const target = doc.createElement('div');
const supported = typeof target.setHTML === 'function';
renderHtml(target, input);
const checks = supported ? {
formatRetained: target.querySelector('strong')?.textContent === 'pembaca',
scriptRemoved: !target.querySelector('script'),
handlerRemoved: !target.querySelector('[onclick]'),
dangerousURLRemoved: !!target.querySelector('a') && !target.querySelector('a').hasAttribute('href'),
} : { textOnly: target.textContent === input && target.children.length === 0 };
const fallback = doc.createElement('div');
Object.defineProperty(fallback, 'setHTML', { value: undefined });
renderHtml(fallback, input);
checks.fallbackTextOnly = fallback.textContent === input && fallback.children.length === 0;
if (!Object.values(checks).every(Boolean)) throw new Error('Pemeriksaan sanitasi gagal');
const result = { supported, output: target.innerHTML, checks };
console.log(result);
return result;
})()
Hasil uji terbatas, bukan jaminan semua browser
Hasil Pengujian Sanitasi Browser
Contoh di atas dijalankan melalui browser otomatis pada 31 Oktober 2026. Browser melaporkan HeadlessChrome/145.0.0.0 pada Linux. API tersedia pada sesi tersebut. Lima pemeriksaan lulus: format strong tetap ada, elemen skrip hilang, atribut onclick hilang, URL javascript: hilang, dan fallback menghasilkan teks tanpa elemen anak.
Keluaran HTML yang benar-benar diamati pada sesi tersebut:
<p>Halo <strong>pembaca</strong></p><a>tautan</a>Elemen gambar pada masukan juga tidak dipertahankan oleh konfigurasi bawaan yang diuji. Jangan menganggap semua markup aman pasti dipertahankan: jika aplikasi memerlukan gambar, tabel, atribut khusus, atau tautan tertentu, uji kebutuhan itu secara terpisah. String versi di atas berasal dari user-agent browser pengujian; hasil ini bukan pengujian Firefox 148, Safari, browser perangkat pengguna, atau seluruh kemungkinan serangan XSS.
Fallback sengaja mengorbankan format
Penerapan Fallback yang Aman
Cabang fallback menggunakan textContent. Karena itu, pembaca akan melihat tanda HTML sebagai teks bila setHTML tidak tersedia. Ini pilihan yang disengaja agar aplikasi tidak diam-diam beralih ke penyisipan HTML mentah. Pemeriksaan fallback di contoh mematikan metode hanya pada elemen uji, bukan mengubah API browser secara global.
Hindari sanitasi yang dibatalkan sendiri
Dokumentasi MDN memperingatkan agar hasil yang sudah disanitasi tidak diserialisasi lalu dimasukkan kembali memakai innerHTML. Sanitasi bergantung pada konteks elemen. Jika perlu memindahkan string HTML ke elemen lain, lakukan sanitasi lagi pada tujuan dengan metode aman. Jangan memperlakukan pembacaan target.innerHTML untuk pemeriksaan hasil sebagai izin menyisipkan string itu ke tempat lain tanpa sanitasi.
Uji juga kegagalan konfigurasi, markup yang memang dibutuhkan aplikasi, serta jalur lain yang masih menggunakan penyisipan HTML mentah. Autentikasi, otorisasi, validasi server, dan Content Security Policy tetap memiliki peran masing-masing. Lulus pada masukan contoh ini tidak membuktikan aplikasi bebas XSS.
Sumber dan batas kontribusi
Rujukan dan Sumber Terkait
Berita rilis yang menjadi titik awal: Goodbye innerHTML, Hello setHTML: Stronger XSS Protection in Firefox 148, oleh Tom Schuster, Frederik Braun, dan Christoph Kerschbaumer di Mozilla Hacks, terbit 24 Februari 2026. Situs sumber menyatakan lisensi CC BY-SA 3.0 atau versi lebih baru, kecuali dinyatakan lain. Panduan ini mengubah susunan serta penjelasan, menambahkan contoh deteksi fitur, fallback, dan hasil uji terbatas; adaptasi teks ini tersedia dengan CC BY-SA 3.0. Mozilla tidak menyatakan dukungan terhadap panduan ini.
Rujukan teknis: MDN: Element.setHTML(), termasuk konfigurasi sanitasi dan risiko mem-parsing ulang hasil. Penyusunan dan pengujian otomatis dibantu AI. Hasil uji di atas hanya mencakup lingkungan dan masukan yang disebutkan, bukan pengalaman pengujian manusia atau audit keamanan menyeluruh.
