Entitas HTML adalah cara menuliskan sebuah karakter agar browser menampilkannya sebagai teks, bukan memperlakukannya sebagai markup. Ketik < mentah di dalam konten Anda dan browser langsung membacanya sebagai awal sebuah tag; tulis < sebagai gantinya dan ia tampil sebagai < literal di halaman. Pertukaran itulah inti dari encoding entitas HTML.
Ada lima karakter yang membawa makna khusus dalam HTML, dan inilah yang paling sering Anda escape (loloskan): <, >, &, ", dan '. Anda meng-escape-nya karena dua alasan. Pertama adalah tampilan: Anda ingin menampilkan kode atau markup sebagai teks. Kedua, dan yang lebih penting, adalah keamanan: meng-escape masukan yang tidak tepercaya adalah fondasi untuk menghentikan cross-site scripting (XSS).
Ada tiga cara yang bisa saling dipertukarkan untuk menuliskan entitas apa pun, yaitu bernama (<), desimal (<), dan heksadesimal (<), dan ketiganya menghasilkan karakter yang sama. Pertanyaan yang lebih rumit adalah kapan harus meng-escape dan dengan apa, karena jawaban yang tepat bergantung pada di mana nilai itu mendarat: teks HTML, sebuah atribut, sebuah skrip, atau sebuah URL. Panduan ini menelusuri notasinya, kumpulan karakter yang dipesan (reserved), matriks keputusan berdasarkan konteks, serta jebakan yang paling sering menjerat orang.
Apa itu entitas HTML? (anatomi)
Entitas HTML, yang juga disebut referensi karakter (character reference), adalah kode pendek yang menggantikan satu karakter tunggal. Setiap entitas dimulai dengan ampersand & dan diakhiri dengan titik koma ;. Apa yang berada di antara keduanya menentukan karakter mana yang Anda dapatkan.
Ada tiga bentuk:
&name;— referensi bernama, seperti<atau©.&#decimal;— referensi numerik desimal, seperti<.&#xhex;— referensi numerik heksadesimal, seperti<.
Browser membaca referensi tersebut, mencari karakter yang ditunjuknya, lalu menampilkan satu karakter itu. Tidak ada yang berubah pada hasil yang terlihat: < dan < mentah tampil identik. Satu-satunya perbedaan adalah entitas diperlakukan sebagai teks, tidak pernah sebagai awal sebuah tag.
Tiga notasi: bernama, desimal, heksadesimal
Ketiga notasi merujuk pada code point Unicode yang sama; perbedaannya hanya pada cara penulisan. Entitas bernama adalah bentuk yang mudah dibaca tetapi hanya ada untuk karakter yang memiliki nama terdefinisi. Entitas desimal menuliskan code point dalam basis 10. Entitas heksadesimal menuliskan code point yang sama dalam basis 16, yang memetakan satu-ke-satu ke notasi U+XXXX yang Anda lihat di standar Unicode.
| Karakter | Bernama | Desimal | Hex |
|---|---|---|---|
< | < | < | < |
& | & | & | & |
© | © | © | © |
é | é | é | é |
Karena hex mencerminkan U+XXXX secara langsung (é adalah U+00E9, sehingga é), banyak developer memilihnya saat mereka mendokumentasikan atau menalar tentang sebuah code point tertentu. Untuk markup sehari-hari, entitas bernama paling enak dibaca.
Lima karakter dipesan yang wajib Anda escape
Inilah karakter spesial HTML yang mengubah cara browser mengurai sebuah dokumen. Jika salah satunya muncul dalam konten yang seharusnya ditampilkan dan bukan dieksekusi, escape karakter itu.
| Karakter | Bernama | Desimal | Hex | Yang rusak jika tidak Anda escape |
|---|---|---|---|---|
< | < | < | < | Memulai sebuah tag — browser membaca teks berikutnya sebagai markup |
> | > | > | > | Menutup tag terlalu dini |
& | & | & | & | Memulai sebuah entitas — sisanya bisa salah dibaca sebagai referensi |
" | " | " | " | Mengakhiri nilai atribut berkutip ganda terlalu cepat |
' | ' | ' | ' | Mengakhiri nilai atribut berkutip tunggal terlalu cepat |
Entitas ampersand HTML adalah akar dari seluruh sistem ini. Karakter & memulai setiap entitas, jadi ia harus di-escape lebih dulu. Kalau Anda escape tanda kurung sudut sebelum ampersand, Anda justru akan meng-escape ulang & di dalam entitas yang baru saja Anda buat. Lebih lanjut soal jebakan ini di bawah.
Kapan Anda benar-benar perlu meng-escape? (sadar konteks)
Di sinilah sebagian besar bug dan sebagian besar kerentanan berdiam. Prinsip intinya singkat: escape pada saat output, sesuai dengan konteks tempat nilai itu mendarat. Sebuah nilai yang aman di satu tempat bisa berbahaya di tempat lain, jadi encoding yang Anda terapkan harus cocok dengan tujuannya.
Konten elemen HTML
Saat Anda menaruh sebuah nilai di antara tag, misalnya di dalam <p>, sebuah <div>, atau sebuah <td>, escape <, >, dan &. Meng-escape tanda kutip di sini tidak berbahaya tetapi tidak perlu. Jika Anda ingin menampilkan teks <strong> sebagai karakter literal alih-alih membuat kata berikutnya menjadi tebal, encode menjadi <strong> dan browser mencetak tag itu, bukan menerapkannya.
Nilai atribut HTML
Di dalam atribut, karakter kutip menjadi krusial. Jika sebuah nilai berada di title="…" dan mengandung " yang tidak di-escape, ia akan mengakhiri atribut lebih awal dan memungkinkan penyerang menambahkan atribut baru, sebuah vektor XSS klasik. Escape " (dan idealnya ') dalam konteks atribut. Nilai seperti He said "hi" harus menjadi He said "hi" agar tetap tertahan.
Di dalam <script> atau JavaScript inline
Entitas HTML tidak membantu di sini. String yang dibangun ke dalam blok <script> atau penangan event inline membutuhkan escaping string JavaScript atau JSON, bukan referensi karakter. Menulis " di dalam string literal JS menghasilkan enam karakter literal itu, bukan sebuah tanda kutip. Untuk konteks ini, gunakan alat JSON Escape, dan baca panduan lengkap escaping string JSON untuk aturan \uXXXX yang sebenarnya berlaku di dalam skrip.
Di dalam sebuah URL
Sebuah URL punya skema escaping-nya sendiri: percent-encoding. Entitas HTML tidak akan membuat sebuah nilai aman-URL. String a&b c berada dalam query sebagai a%26b%20c, bukan a&b c; spasi tetap merusak URL, dan & tetap memisahkan parameter. Gunakan URL Decoder & Encoder untuk ini, dan panduan encoding dan decoding URL untuk aturan lengkap soal karakter dipesan (reserved) versus tak-dipesan (unreserved).
Matriks keputusan
| Konteks | Escape dengan | Contoh | Pilihan keliru yang gagal |
|---|---|---|---|
| Konten elemen HTML | Entitas HTML (< > &) | <strong> → <strong> | Membiarkan < mentah menyuntikkan sebuah tag |
| Nilai atribut HTML | Entitas HTML (" ' krusial) | "hi" → "hi" | " yang tidak di-escape membobol keluar |
<script> / JS inline | Escaping string JS / JSON | " → \" | Entitas HTML inert di dalam JS |
| URL / query string | Percent-encoding | spasi → %20 | & dan entitas tetap merusak URL |
Bernama vs numerik: mana yang sebaiknya Anda pakai?
Entitas bernama mudah dibaca dan merupakan default yang tepat untuk karakter dipesan yang umum serta simbol yang sudah dikenal, seperti <, &, ©, dan —. Namun, entitas bernama hanya ada untuk karakter yang memiliki nama terdefinisi. Entitas numerik, desimal maupun hex, dapat meng-encode code point apa pun, termasuk yang tidak punya nama, sehingga menjadikannya cadangan universal. Saat Anda tidak bisa menjamin bahwa sistem penerima mendukung suatu entitas bernama tertentu, numerik adalah pilihan yang aman.
Mengapa apostrof adalah ' dan bukan '
Entitas bernama ' baru diperkenalkan pada HTML5 dan XML. Ia tidak terdefinisi di HTML4, sehingga sejumlah parser lama dan klien email menampilkannya sebagai teks literal ' alih-alih sebuah apostrof. Referensi numerik ' (beserta kembarannya dalam desimal ') menunjuk ke karakter yang persis sama, U+0027, dan dipahami oleh setiap parser yang pernah ditulis sesuai standar. Library escaping yang teruji baik seperti he mengeluarkan ' untuk kutip tunggal justru karena alasan ini, dan encoder yang baik mengikuti konvensi tersebut agar keluarannya aman ditaruh di konteks HTML, XML, atau atribut mana pun.
Charset vs entitas: kapan meng-encode non-ASCII
Sebuah character set, seperti UTF-8, menentukan bagaimana karakter disimpan sebagai byte. Sebuah entitas adalah cara mengeja sebuah karakter hanya dengan ASCII biasa (&, #, ;, huruf, angka). Keduanya adalah lapisan yang berbeda, dan mencampuradukkannya menyebabkan encoding yang tidak perlu.
Pada halaman UTF-8 — yang berarti hampir setiap halaman modern yang mendeklarasikan <meta charset="utf-8"> — huruf beraksen, tanda hubung, dan emoji adalah karakter mentah yang valid. Biarkan é, —, dan 😀 apa adanya. Meng-encode semuanya menjadi entitas hanya relevan saat teks harus bertahan melewati charset single-byte warisan atau sistem yang merusak UTF-8 mentah; sebuah mode “encode semua non-ASCII” tersedia untuk kasus-kasus itu. Jika Anda ragu bagaimana byte, code point, dan karakter saling berhubungan, panduan encoding UTF-8, UTF-16 dan Unicode memaparkan modelnya.
Jebakan umum entitas HTML
Meng-escape & terakhir menyebabkan double-escaping
Urutan itu penting. Jika Anda mengganti < dan > sebelum &, entitas yang baru saja Anda buat (<, >) ikut ter-escape & di depannya, sehingga < berakhir menjadi &lt; dan tampil sebagai teks literal <. Selalu escape & lebih dulu, baru sisanya. Satu aturan ini mencegah bug encoding yang paling sering terjadi.
Double-encoding teks yang sudah ter-escape
Menjalankan teks yang sudah ter-escape melalui encoder lagi akan meng-encode-nya ulang. & menjadi &amp;, dan pengunjung melihat & di halaman alih-alih &. Escape tepat sekali, pada saat output. Jika sebuah nilai melewati beberapa lapisan, pastikan hanya satu di antaranya yang meng-escape.
Mojibake saat decoding
Arah sebaliknya punya jebakannya sendiri. Decode dengan charset yang salah, atau decode dua kali, dan Anda mendapatkan keluaran kacau, mojibake yang klasik. Jika sebuah halaman menampilkan &lt; literal di tempat yang Anda harapkan <, tempelkan ke Decoder Entitas HTML untuk melihat persis apa yang dihasilkan entitas tersebut; alat ini menangani bernama, desimal, hex, bahkan referensi warisan tak-berakhir seperti © tanpa titik koma penutup.
Memercayai escaping sebagai obat XSS yang lengkap
Escaping adalah garis pertahanan pertama, bukan satu-satunya. Karena HTML memiliki beberapa konteks dengan aturan berbeda, meng-escape untuk konteks yang salah meninggalkan lubang: kutip di atribut, escaping JS di skrip, percent-encoding di URL. Pasangkan escaping yang benar dan sadar konteks dengan Content Security Policy serta auto-escaping bawaan framework Anda. Anggap encoding entitas sebagai fondasi, dengan CSP dan default framework dilapiskan di atasnya.
Cara meng-encode dan decode entitas dalam praktik
Saat Anda membangun HTML secara manual, Anda meng-escape-nya sendiri. Berikut adalah escapeHtml() yang benar yang menangani urutan &-lebih-dulu, beserta praktik yang lebih baik untuk kode aplikasi sungguhan.
// Lima karakter dipesan dan entitas amannya:
// < → < > → > & → & " → " ' → '
function escapeHtml(str) {
return str
.replace(/&/g, '&') // & DULU, agar entitas berikutnya tidak ter-double-escape
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, '''); // bentuk numerik — aman di HTML4, HTML5 dan XML
}
const userInput = `<a href="x">Tom & Jerry's</a>`;
const safe = escapeHtml(userInput);
// → <a href="x">Tom & Jerry's</a>
// Lebih baik di kode aplikasi: biarkan platform meng-escape untuk Anda.
// el.textContent = userInput; // browser meng-escape; tanpa replace manual
// React / Vue / Angular meng-escape teks interpolasi secara default
// Template server (Jinja, ERB, Blade) auto-escape kecuali Anda menonaktifkannya
Fungsi buatan-tangan ini berguna untuk memahami apa yang terjadi dan untuk konversi sekali pakai, tetapi di produksi lebih baik gunakan jalur bawaan. Mengatur element.textContent membiarkan browser meng-escape untuk Anda, dan framework modern meng-escape nilai interpolasi secara otomatis. Simpan escaping manual untuk kasus-kasus yang tidak dicakup platform.
Untuk pekerjaan dadakan, Encoder Entitas HTML meng-escape kumpulan karakter dipesan (bernama, desimal, atau hex), dan Decoder Entitas HTML membalikkannya. Keduanya adalah kebalikan persis untuk karakter dipesan, jadi Anda bisa melakukan round-trip teks melalui keduanya tanpa kehilangan.
Pertanyaan yang sering diajukan
Apa itu entitas HTML?
Entitas HTML adalah kode pendek, dimulai dengan & dan diakhiri dengan ;, yang mewakili satu karakter tunggal. Browser menampilkan karakter yang ditunjuk entitas itu alih-alih memperlakukannya sebagai markup. Misalnya, < menampilkan < literal, dan & menampilkan & literal.
Karakter mana yang perlu saya escape dalam HTML?
Lima karakter spesial HTML yang dipesan: <, >, &, ", dan '. Dalam konten elemen Anda terutama membutuhkan <, >, dan &; dalam nilai atribut, tanda kutip " dan ' juga menjadi krusial. Escape ampersand & lebih dulu agar entitas lain tidak ter-double-escape.
Sebaiknya saya pakai entitas bernama atau numerik (desimal/hex)?
Gunakan entitas bernama (<, ©) demi keterbacaan pada karakter yang umum, karena mudah dikenali. Gunakan entitas numerik (desimal < atau hex <) saat Anda perlu meng-encode karakter yang tidak punya nama terdefinisi, atau saat Anda tidak bisa menjamin penerima mendukung suatu entitas bernama tertentu. Kedua bentuk merujuk pada code point yang sama.
Apakah entitas HTML melindungi dari XSS?
Mereka adalah fondasinya, jika diterapkan dengan benar. Meng-escape lima karakter dipesan sebelum menaruh masukan tidak tepercaya ke dalam konten elemen atau atribut HTML menghentikan injeksi tag dan skrip. Tetapi escaping bergantung konteks: blok skrip membutuhkan escaping JavaScript dan URL membutuhkan percent-encoding. Padukan escaping yang benar dan sadar konteks dengan CSP serta auto-escaping framework.
Mengapa halaman saya menampilkan &lt; alih-alih <?
Itu adalah double-escaping. Teks ter-encode dua kali, atau & di-escape setelah tanda kurung sudut, sehingga & di dalam < berubah menjadi &. Pengunjung lalu melihat < sebagai teks literal. Escape tepat sekali dan selalu escape & lebih dulu. Alat decoder bisa memastikan apa yang dihasilkan entitas-entitas tersebut.
Apakah saya perlu meng-escape karakter seperti é, — atau emoji?
Biasanya tidak. Pada halaman yang mendeklarasikan <meta charset="utf-8">, huruf beraksen, tanda hubung, dan emoji adalah karakter mentah yang valid dan tidak perlu encoding — biarkan apa adanya. Encode non-ASCII hanya saat teks harus melewati charset single-byte warisan atau sistem yang merusak UTF-8 mentah.