Bagaimana cara mendekode entitas HTML menggunakan jQuery?


Jawaban:


437

Catatan keamanan: menggunakan jawaban ini (disimpan dalam bentuk aslinya di bawah) dapat memperkenalkan kerentanan XSS ke dalam aplikasi Anda. Anda sebaiknya tidak menggunakan jawaban ini. Baca jawaban lucascaro untuk penjelasan tentang kerentanan dalam jawaban ini, dan gunakan pendekatan dari jawaban itu atau bukan jawaban Mark Amery .

Sebenarnya, cobalah

var decoded = $("<div/>").html(encodedStr).text();

175
Jangan tidak melakukan hal ini dengan masukan yang tidak dipercaya. Banyak browser memuat gambar dan kejadian terkait api bahkan jika node tidak dilampirkan ke DOM. Coba jalankan $("<div/>").html('<img src="http://www.google.com/images/logos/ps_logo2.png" onload=alert(1337)>'). Di Firefox atau Safari, ia mengaktifkan peringatan.
Mike Samuel

@ Mike, jadi apa yang Anda rekomendasikan? jawaban Anda dari .replace () tidak baik jika Anda tidak tahu apa yang Anda ganti ...
ekkis

7
@ekkis, Anda perlu menghapus tag sebelum mencoba mendekodekan entitas. str.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/g, "")atau yang serupa.
Mike Samuel

2
Implementasi yang lebih baik (menurut saya) yang menghapus sebagian besar tag HTML (milik Mike) dari input ada pada jawaban saya atas pertanyaan serupa . Ini juga tidak memiliki overhead jQuery sehingga sangat cocok untuk lingkungan lain.
Robert K

6
@MichaelStum hasil edit Anda di sini membatalkan komentar Mike Samuel dan jawaban terpilih berikutnya, dan melakukannya tanpa benar-benar memperbaiki kerentanan XSS untuk semua versi jQuery (seperti yang dijelaskan dalam jawaban di bawah). Menambahkan peringatan keamanan ke jawaban ini akan masuk akal (dan saya akan melakukannya); membuat diskusi lain di halaman ini tidak masuk akal sementara gagal untuk benar-benar memperbaiki lubang keamanan jelas tidak!
Mark Amery

211

Tanpa jQuery:

function decodeEntities(encodedString) {
  var textArea = document.createElement('textarea');
  textArea.innerHTML = encodedString;
  return textArea.value;
}

console.log(decodeEntities('1 &amp; 2')); // '1 & 2'

Ini bekerja mirip dengan jawaban yang diterima , tetapi aman untuk digunakan dengan input pengguna yang tidak dipercaya.


Masalah keamanan dalam pendekatan serupa

Seperti dicatat oleh Mike Samuel , melakukan ini dengan <div>bukan <textarea>dengan input pengguna yang tidak dipercaya adalah kerentanan XSS, bahkan jika <div>itu tidak pernah ditambahkan ke DOM:

function decodeEntities(encodedString) {
  var div = document.createElement('div');
  div.innerHTML = encodedString;
  return div.textContent;
}

// Shows an alert
decodeEntities('<img src="nonexistent_image" onerror="alert(1337)">')

Namun, serangan ini tidak dimungkinkan terhadap a <textarea>karena tidak ada elemen HTML yang diizinkan konten a<textarea> . Akibatnya, setiap tag HTML yang masih ada dalam string 'disandikan' akan secara otomatis disandikan oleh browser.

function decodeEntities(encodedString) {
    var textArea = document.createElement('textarea');
    textArea.innerHTML = encodedString;
    return textArea.value;
}

// Safe, and returns the correct answer
console.log(decodeEntities('<img src="nonexistent_image" onerror="alert(1337)">'))

Peringatan : Melakukan ini menggunakan jQuery's .html()dan .val()metode alih-alih menggunakan .innerHTMLdan .valuejuga tidak aman * untuk beberapa versi jQuery, bahkan ketika menggunakan atextarea . Ini karena versi jQuery yang lebih lama akan secara sengaja dan eksplisit mengevaluasi skrip yang terkandung dalam string yang diteruskan ke .html(). Karenanya kode seperti ini menunjukkan peringatan di jQuery 1.8:

//<!-- CDATA
// Shows alert
$("<textarea>")
.html("<script>alert(1337);</script>")
.text();

//-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>

* Terima kasih kepada Eru Penkman karena telah menangkap kerentanan ini.


6
Mungkin ide yang baik untuk menghancurkan textarea setelah mengekstraksi nilainya:decodedString = textArea.value; textArea.remove(); return decodedString;
Werner

2
Atau hanya jika versi javascript benar-benar mendukung remove ():if ('remove' in Element.prototype) textArea.remove();
Werner

6
@Werner Begitu fungsi telah keluar, tidak akan ada lagi variabel yang menyimpan referensi sehingga akan dihapus secara otomatis oleh pengumpul sampah .
user2428118

Saya menggunakan ini dalam kombinasi dengan .NET dari kode di belakang klik tombol, dan untuk beberapa alasan jawaban yang diterima menyebabkan postback. Jawaban ini tidak, jadi ini adalah jawaban terbaik untuk saya. Terima kasih!
Snailer

@Snailer $("<div />").html(string).text() akan mengeksekusi semua javascript dalam string yang disediakan , yang saya duga adalah penyebab masalah Anda. Jawaban yang diterima harus diperbarui untuk yang satu ini.
Jbowman

80

Seperti yang dikatakan Mike Samuel, jangan gunakan jQuery.html (). Text () untuk mendekode entitas html karena tidak aman.

Sebagai gantinya, gunakan perender template seperti Mustache.js atau decodeEntities dari komentar @ VyvIT.

Pustaka sabuk utilitas Underscore.js dilengkapi dengan escapedan unescapemetode, tetapi tidak aman untuk input pengguna:

_.escape (string)

_.unescape (string)


2
Ini sebenarnya layak mendapatkan lebih banyak upvotes! Jelas solusi yang saya sukai. Mereka termasuk unescapedalam dokumen sekarang, btw.
lethal-guitar

5
_.unescape("&#39;")menghasilkan hanya "& # 39;" bukannya kutipan tunggal. Apakah ada sesuatu yang saya lewatkan atau garis bawah tidak melarikan diri ke kode entitas HTML seperti yang ditunjukkan pada: w3schools.com/tags/ref_entities.asp
Jason Axelson

6
Bug di github ditutup sebagai "Tidak akan diperbaiki"; itu berarti bahwa solusi ini tidak berfungsi dan tidak akan berfungsi.
Igor Chubin

3
Anda mengatakan bahwa " escapedan unescapemetode Underscore ... tidak aman untuk input pengguna" . Apa yang Anda maksud dengan ini? Kedengarannya seperti omong kosong bagi saya, tapi mungkin saya kehilangan sesuatu - dapatkah Anda menjelaskannya?
Mark Amery

2
@VyvIT Mencoba _.unescape("&lt;img src=fake onerror=alert('boo!')&gt;")(di Chrome / FF / IE). Tapi itu tidak muncul waspada. Mencoba di konsol dan juga memasukkannya ke dalam file JS saya. Hasil yang sama
Vivek Athalye

28

Saya pikir Anda membingungkan metode teks dan HTML. Lihatlah contoh ini, jika Anda menggunakan HTML bagian dalam elemen sebagai teks, Anda akan mendapatkan tag HTML yang didekodekan (tombol kedua). Tetapi jika Anda menggunakannya sebagai HTML, Anda akan mendapatkan tampilan berformat HTML (tombol pertama).

<div id="myDiv">
    here is a <b>HTML</b> content.
</div>
<br />
<input value="Write as HTML" type="button" onclick="javascript:$('#resultDiv').html($('#myDiv').html());" />
&nbsp;&nbsp;
<input value="Write as Text" type="button" onclick="javascript:$('#resultDiv').text($('#myDiv').html());" />
<br /><br />
<div id="resultDiv">
    Results here !
</div>

Tombol pertama menulis: di sini adalah konten HTML .

Tombol kedua menulis: di sini adalah konten <B> HTML </B>.

Omong-omong, Anda dapat melihat plug-in yang saya temukan di jQuery plugin - HTML decode dan encode yang mengkodekan dan mendekode string HTML.


26

Pertanyaannya dibatasi oleh 'with jQuery' tetapi mungkin membantu beberapa orang untuk mengetahui bahwa kode jQuery yang diberikan dalam jawaban terbaik di sini melakukan hal berikut di bawah ini ... ini berfungsi dengan atau tanpa jQuery:

function decodeEntities(input) {
  var y = document.createElement('textarea');
  y.innerHTML = input;
  return y.value;
}

20

Anda dapat menggunakan perpustakaan he , tersedia dari https://github.com/mathiasbynens/he

Contoh:

console.log(he.decode("J&#246;rg &amp J&#xFC;rgen rocked to &amp; fro "));
// Logs "Jörg & Jürgen rocked to & fro"

Saya menantang penulis perpustakaan tentang pertanyaan apakah ada alasan untuk menggunakan perpustakaan ini dalam kode sisi klien demi <textarea>peretasan yang diberikan dalam jawaban lain di sini dan di tempat lain. Dia memberikan beberapa kemungkinan pembenaran:

  • Jika Anda menggunakan node.js serverside, menggunakan pustaka untuk pengkodean / decoding HTML memberi Anda solusi tunggal yang berfungsi baik di sisi klien dan di sisi server.

  • Algoritme penguraian entitas entitas peramban memiliki bug atau tidak ada dukungan untuk beberapa referensi karakter bernama . Sebagai contoh, Internet Explorer akan mendekode dan membuat spasi yang tidak melanggar ( &nbsp;) dengan benar tetapi melaporkannya sebagai ruang biasa alih-alih yang tidak melanggar melalui innerTextproperti elemen DOM , memecahkan <textarea>peretasan (meskipun hanya dengan sedikit cara). Selain itu, IE 8 dan 9 hanya tidak mendukung salah satu referensi karakter baru bernama ditambahkan dalam HTML 5. Penulis ia juga menjadi tuan tes bernama dukungan referensi karakter di http://mathias.html5.org/tests/html / bernama-karakter-referensi / . Di IE 8, ini melaporkan lebih dari seribu kesalahan.

    Jika Anda ingin diisolasi dari bug peramban yang terkait dengan penguraian kode entitas dan / atau dapat menangani serangkaian referensi karakter bernama lengkap, Anda tidak bisa lolos dari <textarea>peretasan; Anda akan membutuhkan perpustakaan seperti dia .

  • Dia hanya merasa sangat baik seperti melakukan hal-hal dengan cara seperti ini.


4
+1 jQuery bukanlah solusi untuk semuanya. Gunakan alat yang tepat untuk pekerjaan itu.
Mathias Bynens

Ini adalah cara terbaik untuk mendekode entitas HTML. Semua jawaban lain (pada pertanyaan ini dan pertanyaan serupa) baik menggunakan innerHTML (buat elemen HTML baru, proses kode HTML dan kemudian dapatkan innerHTML dari elemen itu, ini bisa rentan terhadap serangan XSS jika Anda tidak SANGAT hati-hati, lihat lebih banyak ), atau mereka sarankan menggunakan metode underscore.js unescape atau Lodash unescape yang keduanya tidak lengkap (hanya berfungsi untuk beberapa entitas HTML). Perpustakaannya adalah pilihan paling lengkap dan aman!
ands

18

menyandi:

$("<textarea/>").html('<a>').html();      // return '&lt;a&gt'

membaca sandi:

$("<textarea/>").html('&lt;a&gt').val()   // return '<a>'

3
sudah ada jawaban yang berfungsi, dan hampir identik dengan ini. Kami tidak memerlukan jawaban rangkap
markasoftware

4
Ini jawaban yang valid. Jawaban tom menggunakan elemen DIV, yang membuat jawaban itu rentan terhadap XSS.
Francisco Hodge

2
Ini adalah jawaban terbaik untuk kejelasan.
Dan Randolph

4

Menggunakan

myString = myString.replace( /\&amp;/g, '&' );

Paling mudah untuk melakukannya di sisi server karena ternyata JavaScript tidak memiliki pustaka asli untuk menangani entitas, juga saya tidak menemukan apa pun di dekat bagian atas hasil pencarian untuk berbagai kerangka kerja yang memperluas JavaScript.

Cari "entitas HTML JavaScript", dan Anda mungkin menemukan beberapa perpustakaan hanya untuk tujuan itu, tetapi mereka semua mungkin dibangun di sekitar logika di atas - ganti, entitas dengan entitas.


0

Saya hanya harus memiliki charater entitas HTML (⇓) sebagai nilai untuk tombol HTML. Kode HTML terlihat bagus dari awal di browser:

<input type="button" value="Embed & Share  &dArr;" id="share_button" />

Sekarang saya menambahkan toggle yang juga harus menampilkan karakter. Ini solusi saya

$("#share_button").toggle(
    function(){
        $("#share").slideDown();
        $(this).attr("value", "Embed & Share " + $("<div>").html("&uArr;").text());
    }

Ini menampilkan ⇓ lagi di tombol. Saya harap ini bisa membantu seseorang.


Simpler akan menggunakan urutan escape unicode (yaitu "Embed & Share \u21d1"), atau lebih baik lagi hanya "Embed & Share ⇑"jika Anda dapat melayani skrip Anda dalam UTF-8 (atau UTF-16, atau penyandian lain yang mendukung karakter ⇑). Menggunakan elemen DOM untuk mem-parsing entitas HTML hanya untuk memanggang karakter unicode sewenang-wenang menjadi string JavaScript adalah pendekatan licik dan kreatif yang akan membuat Rube Goldberg bangga, tetapi bukan praktik yang baik; unicode escapes ada dalam bahasa khusus untuk menangani use case ini.
Mark Amery

0

Anda harus membuat fungsi khusus untuk entitas html:

function htmlEntities(str) {
return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g,'&gt;').replace(/"/g, '&quot;');
}

Saya tidak tahu, itu membantu saya jadi +1 l)
Szymon Toda

mungkin itu ditolak karena hanya menangani beberapa entitas.
Jasen

Pertanyaan awal adalah bagaimana memecahkan kode entitas - ini melakukan kebalikan dari apa yang diinginkan; itu mengkodekan serangkaian karakter yang sangat terbatas ke dalam entitas. Seperti kata tooltip suara turun, "Jawaban ini tidak berguna". Saya terkejut bahwa setelah 4 tahun masih memiliki skor bersih-positif.
Stephen P

0

Misalkan Anda memiliki String di bawah ini.

Kabin Deluxe kami hangat, nyaman & amp; nyaman

var str = $("p").text(); // get the text from <p> tag
$('p').html(str).text();  // Now,decode html entities in your variable i.e 

str dan tetapkan kembali ke

menandai.

itu dia.


0

Untuk pengguna ExtJS, jika Anda sudah memiliki string yang disandikan, misalnya ketika nilai yang dikembalikan dari fungsi perpustakaan adalah konten innerHTML, pertimbangkan fungsi ExtJS ini:

Ext.util.Format.htmlDecode(innerHtmlContent)

Ini hanya akan berfungsi untuk 5 entitas HTML. Anda dapat melihatnya di dokumentasi dan kode sumber .
ands

0

Perpanjang kelas String:

String::decode = ->
  $('<textarea />').html(this).text()

dan gunakan sebagai metode:

"&lt;img src='myimage.jpg'&gt;".decode()

0

Coba ini :

var htmlEntities = "&lt;script&gt;alert('hello');&lt;/script&gt;";
var htmlDecode =$.parseHTML(htmlEntities)[0]['wholeText'];
console.log(htmlDecode);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

parseHTML adalah sebuah Fungsi di perpustakaan Jquery dan itu akan mengembalikan array yang menyertakan beberapa detail tentang String yang diberikan.

dalam beberapa kasus, String sedang besar, jadi fungsinya akan memisahkan konten ke banyak indeks ..

dan untuk mendapatkan semua data indeks Anda harus pergi ke indeks apa pun, kemudian akses ke indeks yang disebut "wholeText".

Saya memilih indeks 0 karena ini akan berfungsi dalam semua kasus (String kecil atau string besar).


Sementara cuplikan kode ini mungkin solusinya, termasuk penjelasan sangat membantu untuk meningkatkan kualitas posting Anda. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa depan, dan orang-orang itu mungkin tidak tahu alasan untuk saran kode Anda.
Johan

Penjelasan ini ditambahkan ... Terima kasih :)
Fawaz Al Romy

-1

Berikut ini masih ada satu masalah: String yang dilompati tidak terlihat dapat dibaca ketika ditugaskan ke nilai input

var string = _.escape("<img src=fake onerror=alert('boo!')>");
$('input').val(string);

Exapmle: https://jsfiddle.net/kjpdwmqa/3/


Ini bukan jawaban untuk pertanyaan itu. OP meminta untuk mendekode (unescape) entitas HTML, tetapi dalam jawaban ini Anda menggunakan escapemetode Underscore.js. Juga tidak ada penjelasan bagaimana sampel kode Anda harus menyelesaikan masalah OP.
ands

-1

Atau, ada juga perpustakaan untuk itu ..

di sini, https://cdnjs.com/libraries/he

npm install he                 //using node.js

<script src="js/he.js"></script>  //or from your javascript directory

Penggunaannya adalah sebagai berikut ...

//to encode text 
he.encode('© Ande & Nonso® Company LImited 2018');  

//to decode the 
he.decode('&copy; Ande &amp; Nonso&reg; Company Limited 2018');

Bersulang.


Sudah ada jawaban tentang perpustakaannya yang lengkap, dengan contoh kode sederhana dan penjelasan yang baik mengapa dan kapan Anda harus menggunakan perpustakaan itu .
ands

-3

Untuk mendekode Entitas HTML dengan jQuery, cukup gunakan fungsi ini:

function html_entity_decode(txt){
    var randomID = Math.floor((Math.random()*100000)+1);
    $('body').append('<div id="random'+randomID+'"></div>');
    $('#random'+randomID).html(txt);
    var entity_decoded = $('#random'+randomID).html();
    $('#random'+randomID).remove();
    return entity_decoded;
}

Cara Penggunaan:

Javascript:

var txtEncoded = "&aacute; &eacute; &iacute; &oacute; &uacute;";
$('#some-id').val(html_entity_decode(txtEncoded));

HTML:

<input id="some-id" type="text" />

-3

Cara termudah adalah dengan menetapkan pemilih kelas ke elemen Anda dan kemudian gunakan kode berikut:

$(function(){
    $('.classSelector').each(function(a, b){
        $(b).html($(b).text());
    });
});

Tidak ada lagi yang dibutuhkan!

Saya punya masalah ini dan menemukan solusi yang jelas dan berfungsi dengan baik.


Ini bukan jawaban untuk pertanyaan OP. OP meminta untuk mendekode entitas HTML dalam STRING, BUKAN hanya ini tidak menyelesaikan masalah OP tetapi juga menggantikan entitas HTML yang lolos dalam elemen HTML dengan yang belum dibuka yang seharusnya tidak dilakukan.
ands

-3

Saya pikir itu adalah kebalikan dari solusi yang dipilih.

var decoded = $("<div/>").text(encodedStr).html();
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.