Menghapus entitas HTML dalam Javascript?

176

Saya memiliki beberapa kode Javascript yang berkomunikasi dengan backend XML-RPC. XML-RPC mengembalikan string dari formulir:

<img src='myimage.jpg'>

Namun, ketika saya menggunakan Javascript untuk memasukkan string ke HTML, mereka membuat secara harfiah. Saya tidak melihat gambar, saya benar-benar melihat string:

<img src='myimage.jpg'>

Dugaan saya adalah bahwa HTML sedang melarikan diri melalui saluran XML-RPC.

Bagaimana saya bisa menghapus string dalam Javascript? Saya mencoba teknik-teknik pada halaman ini, tidak berhasil: http://paulschreiber.com/blog/2008/09/20/javascript-how-to-unescape-html-entities/

Apa cara lain untuk mendiagnosis masalah ini?

Joseph Turian
sumber

Jawaban:

176

EDIT: Anda harus menggunakan DOMParser API seperti yang disarankan Wladimir , saya mengedit jawaban saya sebelumnya karena fungsi yang diposting memperkenalkan kerentanan keamanan.

Cuplikan berikut adalah kode jawaban lama dengan modifikasi kecil: menggunakan textareabukan divmengurangi kerentanan XSS, tetapi masih bermasalah di IE9 dan Firefox.

function htmlDecode(input){
  var e = document.createElement('textarea');
  e.innerHTML = input;
  // handle case of empty input
  return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
}

htmlDecode("&lt;img src='myimage.jpg'&gt;"); 
// returns "<img src='myimage.jpg'>"

Pada dasarnya saya membuat elemen DOM secara terprogram, menetapkan HTML yang dikodekan ke dalamnyaHTML dan mengambil nilai simpul dari simpul teks yang dibuat pada penyisipan innerHTML. Karena itu hanya membuat elemen tetapi tidak pernah menambahkannya, tidak ada situs HTML yang dimodifikasi.

Ini akan bekerja lintas-browser (termasuk browser lama) dan menerima semua Entitas Karakter HTML .

EDIT: Versi lama dari kode ini tidak berfungsi di IE dengan input kosong, seperti dibuktikan di sini di jsFiddle (lihat di IE). Versi di atas berfungsi dengan semua input.

UPDATE: tampaknya ini tidak berfungsi dengan string besar, dan itu juga memperkenalkan kerentanan keamanan , lihat komentar.

CMS
sumber
Anda mengerti, Anda berubah menjadi ', jadi izinkan saya menghapus komentar saya kembali, thx, ini berfungsi dengan baik, +1
YOU
1
@ S.Mark: &apos;bukan milik Entitas HTML 4, itu sebabnya! w3.org/TR/html4/sgml/entities.html fishbowl.pastiche.org/2003/07/01/the_curse_of_apos
CMS
2
Lihat juga @ kender's note tentang keamanan yang buruk dari pendekatan ini.
Joseph Turian
2
Lihat catatan saya untuk @kender tentang pengujian miskin ia lakukan;)
Roatin Marth
24
Fungsi ini merupakan bahaya keamanan, kode JavaScript akan berjalan meskipun elemen tidak ditambahkan ke DOM. Jadi ini hanya sesuatu untuk digunakan jika string input dipercaya. Saya menambahkan jawaban saya sendiri yang menjelaskan masalah ini dan memberikan solusi yang aman. Sebagai efek samping, hasilnya tidak terputus jika ada beberapa node teks.
Wladimir Palant
375

Sebagian besar jawaban yang diberikan di sini memiliki kelemahan besar: jika string yang Anda coba konversi tidak dipercaya maka Anda akan berakhir dengan kerentanan Cross-Site Scripting (XSS) . Untuk fungsi dalam jawaban yang diterima , pertimbangkan hal berikut:

htmlDecode("<img src='dummy' onerror='alert(/xss/)'>");

String di sini berisi tag HTML yang tidak terhapus, jadi alih-alih mendekode apa pun htmlDecodefungsi tersebut sebenarnya akan menjalankan kode JavaScript yang ditentukan di dalam string.

Ini dapat dihindari dengan menggunakan DOMParser yang didukung di semua browser modern :

function htmlDecode(input) {
  var doc = new DOMParser().parseFromString(input, "text/html");
  return doc.documentElement.textContent;
}

console.log(  htmlDecode("&lt;img src='myimage.jpg'&gt;")  )    
// "<img src='myimage.jpg'>"

console.log(  htmlDecode("<img src='dummy' onerror='alert(/xss/)'>")  )  
// ""

Fungsi ini dijamin tidak menjalankan kode JavaScript apa pun sebagai efek samping. Tag HTML apa pun akan diabaikan, hanya konten teks yang akan dikembalikan.

Catatan kompatibilitas : Parsing HTML dengan DOMParsermembutuhkan setidaknya Chrome 30, Firefox 12, Opera 17, Internet Explorer 10, Safari 7.1 atau Microsoft Edge. Jadi semua browser tanpa dukungan sudah melewati EOL mereka dan pada 2017 satu-satunya yang masih dapat dilihat di alam liar kadang-kadang adalah versi Internet Explorer dan Safari yang lebih lama (biasanya ini masih tidak cukup mengganggu).

Wladimir Palant
sumber
19
Saya pikir jawaban ini adalah yang terbaik karena menyebutkan kerentanan XSS.
Константин Ван
2
Perhatikan bahwa (sesuai dengan referensi Anda) DOMParsertidak mendukung "text/html"sebelum Firefox 12.0, dan masih ada beberapa versi browser terbaru yang bahkan tidak mendukungDOMParser.prototype.parseFromString() . Menurut referensi Anda, DOMParsermasih merupakan teknologi eksperimental, dan stand-in menggunakan innerHTMLproperti yang, seperti yang Anda tunjukkan sebagai jawaban atas pendekatan saya , memiliki kerentanan XSS ini (yang seharusnya diperbaiki oleh vendor browser).
PointedEars
4
@PointedEars: Siapa yang peduli dengan Firefox 12 pada tahun 2016? Yang bermasalah adalah Internet Explorer hingga 9.0 dan Safari hingga 7.0. Jika seseorang tidak mampu mendukung mereka (yang diharapkan akan segera menjadi semua orang) maka DOMParser adalah pilihan terbaik. Jika tidak - ya, hanya memproses entitas yang akan menjadi pilihan.
Wladimir Palant
4
@PointedEars: <script>tag yang tidak dijalankan bukanlah mekanisme keamanan, aturan ini hanya menghindari masalah pengaturan waktu yang rumit jika pengaturan innerHTMLdapat menjalankan skrip sinkron sebagai efek samping. Sanitasi kode HTML adalah urusan rumit dan innerHTMLbahkan tidak mencoba - sudah karena halaman web mungkin benar-benar bermaksud untuk mengatur inline event handler. Ini sama sekali bukan mekanisme yang ditujukan untuk data yang tidak aman, berhenti penuh.
Wladimir Palant
1
@ ИльяЗеленько: Apakah Anda berencana untuk menggunakan kode ini dalam lingkaran yang ketat atau mengapa kinerja itu penting? Jawaban Anda lagi rentan terhadap XSS, apakah itu benar-benar layak?
Wladimir Palant
37

Jika Anda menggunakan jQuery:

function htmlDecode(value){ 
  return $('<div/>').html(value).text(); 
}

Jika tidak, gunakan Object Encoder Strictly Software , yang memiliki htmlDecode()fungsi sangat baik .

Chris Fulstow
sumber
59
Jangan (ulangi TIDAK) menggunakan ini untuk konten yang dibuat pengguna selain konten yang dihasilkan oleh pengguna ini . Jika ada tag <script> dalam nilai, konten skrip akan dieksekusi!
Malvolio
Saya tidak dapat menemukan lisensi untuk itu di mana pun di situs. Apakah Anda tahu lisensi itu?
TRiG
Ada lisensi di header sumber, ini GPL.
Chris Fulstow
6
YA, fungsi itu membuka jalan bagi XSS: coba htmlDecode ("<script> lansiran (12) </script> 123 & gt;")
Dinis Cruz
apa arti dari $ ('<div />') ?
Echo Yang
13

Caranya adalah dengan menggunakan kekuatan browser untuk mendekode karakter HTML khusus, tetapi tidak mengizinkan browser untuk mengeksekusi hasil seolah-olah itu html yang sebenarnya ... Fungsi ini menggunakan regex untuk mengidentifikasi dan mengganti karakter HTML yang dikodekan, satu karakter pada suatu waktu.

function unescapeHtml(html) {
    var el = document.createElement('div');
    return html.replace(/\&[#0-9a-z]+;/gi, function (enc) {
        el.innerHTML = enc;
        return el.innerText
    });
}
Ben White
sumber
Regex dapat dicocokkan dengan sedikit lebih ketat /\&#?[0-9a-z]+;/gikarena # seharusnya hanya muncul sebagai karakter ke-2 jika sama sekali.
TheAtomicOption
Ini jawaban terbaik. Menghindari kerentanan XSS, dan tidak menghapus tag HTML.
Emmanuel
6

Jawaban CMS berfungsi dengan baik, kecuali HTML yang ingin Anda hapus sangat panjang, lebih panjang dari 65536 karakter. Karena di Chrome HTML bagian dalam terpecah menjadi banyak simpul anak, masing-masing panjangnya paling lama 65.536, dan Anda harus menyatukannya. Fungsi ini juga berfungsi untuk string yang sangat panjang:

function unencodeHtmlContent(escapedHtml) {
  var elem = document.createElement('div');
  elem.innerHTML = escapedHtml;
  var result = '';
  // Chrome splits innerHTML into many child nodes, each one at most 65536.
  // Whereas FF creates just one single huge child node.
  for (var i = 0; i < elem.childNodes.length; ++i) {
    result = result + elem.childNodes[i].nodeValue;
  }
  return result;
}

Lihat jawaban ini tentang innerHTMLpanjang maks untuk info lebih lanjut: https://stackoverflow.com/a/27545633/694469

KajMagnus
sumber
3

Bukan respons langsung terhadap pertanyaan Anda, tetapi bukankah lebih baik bagi RPC Anda untuk mengembalikan beberapa struktur (baik itu XML atau JSON atau apa pun) dengan data gambar tersebut (url dalam contoh Anda) di dalam struktur itu?

Maka Anda bisa menguraikannya dalam javascript Anda dan membangun <img>menggunakan javascript itu sendiri.

Struktur yang Anda terima dari RPC dapat terlihat seperti:

{"img" : ["myimage.jpg", "myimage2.jpg"]}

Saya pikir lebih baik seperti ini, karena menyuntikkan kode yang berasal dari sumber eksternal ke halaman Anda tidak terlihat sangat aman. Membayangkan seseorang membajak skrip XML-RPC Anda dan meletakkan sesuatu yang tidak Anda inginkan di sana (bahkan beberapa javascript ...)

kender
sumber
Apakah pendekatan @CMS di atas memiliki kelemahan keamanan ini?
Joseph Turian
Saya baru saja memeriksa argumen berikut yang diteruskan ke fungsi htmlDecode: htmlDecode ("& lt; img src = 'myimage.jpg' & gt; script & gt; script & gt; document.write ('xxxxx'); & lt; / script & gt;") dan itu menciptakan Elemen <script> </script> yang bisa buruk, imho. Dan saya masih berpikir mengembalikan struktur daripada teks yang akan disisipkan lebih baik, Anda dapat menangani kesalahan dengan baik misalnya.
kender
1
Saya hanya mencoba htmlDecode("&lt;img src='myimage.jpg'&gt;&lt;script&gt;alert('xxxxx');&lt;/script&gt;")dan tidak ada yang terjadi. Saya mendapatkan string html yang didekode kembali seperti yang diharapkan.
Roatin Marth
2

Jawaban Chris bagus & elegan tetapi gagal jika nilainya tidak ditentukan . Hanya peningkatan sederhana membuatnya solid:

function htmlDecode(value) {
   return (typeof value === 'undefined') ? '' : $('<div/>').html(value).text();
}
nerijus
sumber
Jika meningkatkan, maka lakukan:return (typeof value !== 'string') ? '' : $('<div/>').html(value).text();
SynCap
2

Sama-sama ... hanya pembawa pesan ... kredit penuh diberikan ke ourcodeworld.com, tautan di bawah ini.

window.htmlentities = {
        /**
         * Converts a string to its html characters completely.
         *
         * @param {String} str String with unescaped HTML characters
         **/
        encode : function(str) {
            var buf = [];

            for (var i=str.length-1;i>=0;i--) {
                buf.unshift(['&#', str[i].charCodeAt(), ';'].join(''));
            }

            return buf.join('');
        },
        /**
         * Converts an html characterSet into its original character.
         *
         * @param {String} str htmlSet entities
         **/
        decode : function(str) {
            return str.replace(/&#(\d+);/g, function(match, dec) {
                return String.fromCharCode(dec);
            });
        }
    };

Kredit Lengkap: https://ourcodeworld.com/articles/read/188/encode-and-decode-html-entities-using-pure-javascript

decoder7283
sumber
2

Ini adalah solusi paling komprehensif yang saya coba sejauh ini:

const STANDARD_HTML_ENTITIES = {
    nbsp: String.fromCharCode(160),
    amp: "&",
    quot: '"',
    lt: "<",
    gt: ">"
};

const replaceHtmlEntities = plainTextString => {
    return plainTextString
        .replace(/&#(\d+);/g, (match, dec) => String.fromCharCode(dec))
        .replace(
            /&(nbsp|amp|quot|lt|gt);/g,
            (a, b) => STANDARD_HTML_ENTITIES[b]
        );
};
Daniel
sumber
"Yang paling komprehensif"? Sudahkah Anda mencoba menjalankannya terhadap test suite yang benar - benar komprehensif ?
Dan Dascalescu
1

Saya cukup gila untuk melalui dan membuat fungsi ini yang harus cantik, jika tidak sepenuhnya, lengkap:

function removeEncoding(string) {
    return string.replace(/&Agrave;/g, "À").replace(/&Aacute;/g, "Á").replace(/&Acirc;/g, "Â").replace(/&Atilde;/g, "Ã").replace(/&Auml;/g, "Ä").replace(/&Aring;/g, "Å").replace(/&agrave;/g, "à").replace(/&acirc;/g, "â").replace(/&atilde;/g, "ã").replace(/&auml;/g, "ä").replace(/&aring;/g, "å").replace(/&AElig;/g, "Æ").replace(/&aelig;/g, "æ").replace(/&szlig;/g, "ß").replace(/&Ccedil;/g, "Ç").replace(/&ccedil;/g, "ç").replace(/&Egrave;/g, "È").replace(/&Eacute;/g, "É").replace(/&Ecirc;/g, "Ê").replace(/&Euml;/g, "Ë").replace(/&egrave;/g, "è").replace(/&eacute;/g, "é").replace(/&ecirc;/g, "ê").replace(/&euml;/g, "ë").replace(/&#131;/g, "ƒ").replace(/&Igrave;/g, "Ì").replace(/&Iacute;/g, "Í").replace(/&Icirc;/g, "Î").replace(/&Iuml;/g, "Ï").replace(/&igrave;/g, "ì").replace(/&iacute;/g, "í").replace(/&icirc;/g, "î").replace(/&iuml;/g, "ï").replace(/&Ntilde;/g, "Ñ").replace(/&ntilde;/g, "ñ").replace(/&Ograve;/g, "Ò").replace(/&Oacute;/g, "Ó").replace(/&Ocirc;/g, "Ô").replace(/&Otilde;/g, "Õ").replace(/&Ouml;/g, "Ö").replace(/&ograve;/g, "ò").replace(/&oacute;/g, "ó").replace(/&ocirc;/g, "ô").replace(/&otilde;/g, "õ").replace(/&ouml;/g, "ö").replace(/&Oslash;/g, "Ø").replace(/&oslash;/g, "ø").replace(/&#140;/g, "Œ").replace(/&#156;/g, "œ").replace(/&#138;/g, "Š").replace(/&#154;/g, "š").replace(/&Ugrave;/g, "Ù").replace(/&Uacute;/g, "Ú").replace(/&Ucirc;/g, "Û").replace(/&Uuml;/g, "Ü").replace(/&ugrave;/g, "ù").replace(/&uacute;/g, "ú").replace(/&ucirc;/g, "û").replace(/&uuml;/g, "ü").replace(/&#181;/g, "µ").replace(/&#215;/g, "×").replace(/&Yacute;/g, "Ý").replace(/&#159;/g, "Ÿ").replace(/&yacute;/g, "ý").replace(/&yuml;/g, "ÿ").replace(/&#176;/g, "°").replace(/&#134;/g, "†").replace(/&#135;/g, "‡").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&#177;/g, "±").replace(/&#171;/g, "«").replace(/&#187;/g, "»").replace(/&#191;/g, "¿").replace(/&#161;/g, "¡").replace(/&#183;/g, "·").replace(/&#149;/g, "•").replace(/&#153;/g, "™").replace(/&copy;/g, "©").replace(/&reg;/g, "®").replace(/&#167;/g, "§").replace(/&#182;/g, "¶").replace(/&Alpha;/g, "Α").replace(/&Beta;/g, "Β").replace(/&Gamma;/g, "Γ").replace(/&Delta;/g, "Δ").replace(/&Epsilon;/g, "Ε").replace(/&Zeta;/g, "Ζ").replace(/&Eta;/g, "Η").replace(/&Theta;/g, "Θ").replace(/&Iota;/g, "Ι").replace(/&Kappa;/g, "Κ").replace(/&Lambda;/g, "Λ").replace(/&Mu;/g, "Μ").replace(/&Nu;/g, "Ν").replace(/&Xi;/g, "Ξ").replace(/&Omicron;/g, "Ο").replace(/&Pi;/g, "Π").replace(/&Rho;/g, "Ρ").replace(/&Sigma;/g, "Σ").replace(/&Tau;/g, "Τ").replace(/&Upsilon;/g, "Υ").replace(/&Phi;/g, "Φ").replace(/&Chi;/g, "Χ").replace(/&Psi;/g, "Ψ").replace(/&Omega;/g, "Ω").replace(/&alpha;/g, "α").replace(/&beta;/g, "β").replace(/&gamma;/g, "γ").replace(/&delta;/g, "δ").replace(/&epsilon;/g, "ε").replace(/&zeta;/g, "ζ").replace(/&eta;/g, "η").replace(/&theta;/g, "θ").replace(/&iota;/g, "ι").replace(/&kappa;/g, "κ").replace(/&lambda;/g, "λ").replace(/&mu;/g, "μ").replace(/&nu;/g, "ν").replace(/&xi;/g, "ξ").replace(/&omicron;/g, "ο").replace(/&piρ;/g, "ρ").replace(/&rho;/g, "ς").replace(/&sigmaf;/g, "ς").replace(/&sigma;/g, "σ").replace(/&tau;/g, "τ").replace(/&phi;/g, "φ").replace(/&chi;/g, "χ").replace(/&psi;/g, "ψ").replace(/&omega;/g, "ω").replace(/&bull;/g, "•").replace(/&hellip;/g, "…").replace(/&prime;/g, "′").replace(/&Prime;/g, "″").replace(/&oline;/g, "‾").replace(/&frasl;/g, "⁄").replace(/&weierp;/g, "℘").replace(/&image;/g, "ℑ").replace(/&real;/g, "ℜ").replace(/&trade;/g, "™").replace(/&alefsym;/g, "ℵ").replace(/&larr;/g, "←").replace(/&uarr;/g, "↑").replace(/&rarr;/g, "→").replace(/&darr;/g, "↓").replace(/&barr;/g, "↔").replace(/&crarr;/g, "↵").replace(/&lArr;/g, "⇐").replace(/&uArr;/g, "⇑").replace(/&rArr;/g, "⇒").replace(/&dArr;/g, "⇓").replace(/&hArr;/g, "⇔").replace(/&forall;/g, "∀").replace(/&part;/g, "∂").replace(/&exist;/g, "∃").replace(/&empty;/g, "∅").replace(/&nabla;/g, "∇").replace(/&isin;/g, "∈").replace(/&notin;/g, "∉").replace(/&ni;/g, "∋").replace(/&prod;/g, "∏").replace(/&sum;/g, "∑").replace(/&minus;/g, "−").replace(/&lowast;/g, "∗").replace(/&radic;/g, "√").replace(/&prop;/g, "∝").replace(/&infin;/g, "∞").replace(/&OEig;/g, "Œ").replace(/&oelig;/g, "œ").replace(/&Yuml;/g, "Ÿ").replace(/&spades;/g, "♠").replace(/&clubs;/g, "♣").replace(/&hearts;/g, "♥").replace(/&diams;/g, "♦").replace(/&thetasym;/g, "ϑ").replace(/&upsih;/g, "ϒ").replace(/&piv;/g, "ϖ").replace(/&Scaron;/g, "Š").replace(/&scaron;/g, "š").replace(/&ang;/g, "∠").replace(/&and;/g, "∧").replace(/&or;/g, "∨").replace(/&cap;/g, "∩").replace(/&cup;/g, "∪").replace(/&int;/g, "∫").replace(/&there4;/g, "∴").replace(/&sim;/g, "∼").replace(/&cong;/g, "≅").replace(/&asymp;/g, "≈").replace(/&ne;/g, "≠").replace(/&equiv;/g, "≡").replace(/&le;/g, "≤").replace(/&ge;/g, "≥").replace(/&sub;/g, "⊂").replace(/&sup;/g, "⊃").replace(/&nsub;/g, "⊄").replace(/&sube;/g, "⊆").replace(/&supe;/g, "⊇").replace(/&oplus;/g, "⊕").replace(/&otimes;/g, "⊗").replace(/&perp;/g, "⊥").replace(/&sdot;/g, "⋅").replace(/&lcell;/g, "⌈").replace(/&rcell;/g, "⌉").replace(/&lfloor;/g, "⌊").replace(/&rfloor;/g, "⌋").replace(/&lang;/g, "⟨").replace(/&rang;/g, "⟩").replace(/&loz;/g, "◊").replace(/&#039;/g, "'").replace(/&amp;/g, "&").replace(/&quot;/g, "\"");
}

Digunakan seperti ini:

let decodedText = removeEncoding("Ich hei&szlig;e David");
console.log(decodedText);

Cetakan: Ich Heiße David

PS ini butuh waktu setengah jam untuk membuatnya.

David Chopin
sumber
0

Untuk menghapus entitas HTML * dalam JavaScript, Anda dapat menggunakan perpustakaan kecil html-escaper :npm install html-escaper

import {unescape} from 'html-escaper';

unescape('escaped string');

Atau unescapeberfungsi dari Lodash atau Underscore , jika Anda menggunakannya.


*) Mohon perhatikan bahwa fungsi-fungsi ini tidak mencakup semua entitas HTML, tetapi hanya yang paling umum, yaitu &, <, >, ', ". Untuk menghapus semua entitas HTML Anda dapat menggunakan dia perpustakaan.

Łukasz K
sumber
-1

Saya menggunakan ini dalam proyek saya: terinspirasi oleh jawaban lain tetapi dengan parameter ekstra aman, dapat berguna ketika Anda berurusan dengan karakter yang didekorasi

var decodeEntities=(function(){

    var el=document.createElement('div');
    return function(str, safeEscape){

        if(str && typeof str === 'string'){

            str=str.replace(/\</g, '&lt;');

            el.innerHTML=str;
            if(el.innerText){

                str=el.innerText;
                el.innerText='';
            }
            else if(el.textContent){

                str=el.textContent;
                el.textContent='';
            }

            if(safeEscape)
                str=str.replace(/\</g, '&lt;');
        }
        return str;
    }
})();

Dan itu dapat digunakan seperti:

var label='safe <b> character &eacute;ntity</b>';
var safehtml='<div title="'+decodeEntities(label)+'">'+decodeEntities(label, true)+'</div>';
tmx976
sumber
-1

Semua jawaban lain di sini memiliki masalah.

Metode document.createElement ('div') (termasuk yang menggunakan jQuery) menjalankan javascript apa saja yang diteruskan ke dalamnya (masalah keamanan) dan metode DOMParser.parseFromString () memangkas spasi putih. Berikut ini adalah solusi javascript murni yang tidak memiliki masalah:

function htmlDecode(html) {
    var textarea = document.createElement("textarea");
    html= html.replace(/\r/g, String.fromCharCode(0xe000)); // Replace "\r" with reserved unicode character.
    textarea.innerHTML = html;
    var result = textarea.value;
    return result.replace(new RegExp(String.fromCharCode(0xe000), 'g'), '\r');
}

TextArea digunakan khusus untuk menghindari kode js executig. Melewati ini:

htmlDecode('&lt;&amp;&nbsp;&gt;'); // returns "<& >" with non-breaking space.
htmlDecode('  '); // returns "  "
htmlDecode('<img src="dummy" onerror="alert(\'xss\')">'); // Does not execute alert()
htmlDecode('\r\n') // returns "\r\n", doesn't lose the \r like other solutions.
EricP
sumber
1
Tidak, menggunakan tag yang berbeda tidak menyelesaikan masalah. Ini masih kerentanan XSS, coba htmlDecode("</textarea><img src=x onerror=alert(1)>"). Anda memposting ini setelah saya sudah menunjukkan masalah ini pada jawaban oleh Sergio Belevskij.
Wladimir Palant
Saya tidak dapat mereproduksi masalah yang Anda uraikan. Saya memiliki kode Anda di JsFiddle ini, dan tidak ada tampilan lansiran saat berjalan. jsfiddle.net/edsjt15g/1 Bisakah Anda melihatnya? Browser apa yang Anda gunakan?
EricP
2
Saya menggunakan Firefox. Chrome memang menangani skenario ini secara berbeda, sehingga kode tidak dapat dijalankan - bukan sesuatu yang harus Anda andalkan.
Wladimir Palant
-1
var encodedStr = 'hello &amp; world';

var parser = new DOMParser;
var dom = parser.parseFromString(
    '<!doctype html><body>' + encodedStr,
    'text/html');
var decodedString = dom.body.textContent;

console.log(decodedString);
jagjeet
sumber
@Wladimir Palant (penulis AdBlock Plus) sudah memberikan jawaban DOMParser 4 tahun sebelumnya. Sudahkah Anda membaca jawaban sebelumnya sebelum memposting jawaban Anda?
Dan Dascalescu
-7

Ada varian yang 80% seproduktif jawaban di bagian paling atas.

Lihat patokan: https://jsperf.com/decode-html12345678/1

uji kinerja

console.log(decodeEntities('test: &gt'));

function decodeEntities(str) {
  // this prevents any overhead from creating the object each time
  const el = decodeEntities.element || document.createElement('textarea')

  // strip script/html tags
  el.innerHTML = str
    .replace(/<script[^>]*>([\S\s]*?)<\/script>/gmi, '')
    .replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/gmi, '');

  return el.value;
}

Jika Anda perlu meninggalkan tag, maka hapus dua .replace(...)panggilan (Anda dapat meninggalkan yang pertama jika Anda tidak memerlukan skrip).

Илья Зеленько
sumber
6
Selamat, Anda berhasil mengaburkan kerentanan dengan logika sanitasi palsu, semua untuk kemenangan kinerja yang tidak penting dalam praktik. Coba panggil decodeEntities("</textarea '><img src=x onerror=alert(1) \">")di Firefox. Harap berhenti berusaha membersihkan kode HTML dengan ekspresi reguler.
Wladimir Palant