HTML-Entitäten in Javascript entschlüsseln?


177

Ich habe einen Javascript-Code, der mit einem XML-RPC-Backend kommuniziert. Der XML-RPC gibt Zeichenfolgen der folgenden Form zurück:

<img src='myimage.jpg'>

Wenn ich jedoch das Javascript verwende, um die Zeichenfolgen in HTML einzufügen, werden sie buchstäblich gerendert. Ich sehe kein Bild, ich sehe buchstäblich die Zeichenfolge:

<img src='myimage.jpg'>

Ich vermute, dass der HTML-Code über den XML-RPC-Kanal maskiert wird.

Wie kann ich die Zeichenfolge in Javascript entfernen? Ich habe die Techniken auf dieser Seite erfolglos ausprobiert: http://paulschreiber.com/blog/2008/09/20/javascript-how-to-unescape-html-entities/

Was sind andere Möglichkeiten, um das Problem zu diagnostizieren?



Antworten:


177

BEARBEITEN: Sie sollten die DOMParser-API verwenden, wie Wladimir vorschlägt . Ich habe meine vorherige Antwort bearbeitet, da die veröffentlichte Funktion eine Sicherheitslücke eingeführt hat.

Das folgende Snippet ist der Code der alten Antwort mit einer kleinen Änderung: Die Verwendung von a textareaanstelle von a divverringert die XSS-Sicherheitsanfälligkeit, ist jedoch in IE9 und Firefox immer noch problematisch.

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'>"

Grundsätzlich erstelle ich programmgesteuert ein DOM-Element, ordne den codierten HTML-Code seinem innerHTML zu und rufe den nodeValue von dem Textknoten ab, der beim Einfügen von innerHTML erstellt wurde. Da nur ein Element erstellt, aber nie hinzugefügt wird, wird kein Site-HTML geändert.

Es funktioniert browserübergreifend (einschließlich älterer Browser) und akzeptiert alle HTML-Zeichenentitäten .

BEARBEITEN: Die alte Version dieses Codes funktionierte nicht im IE mit leeren Eingaben, wie hier auf jsFiddle (Ansicht im IE) gezeigt. Die obige Version funktioniert mit allen Eingaben.

UPDATE: Dies funktioniert anscheinend nicht mit großen Zeichenfolgen und führt auch zu einer Sicherheitslücke , siehe Kommentare.


Verstanden, du hast zu 'geändert, also lass mich meinen Kommentar zurück löschen, danke, es funktioniert großartig, +1
DU

1
@ S.Mark: &apos;gehört nicht zu den HTML 4 Entities, deshalb! w3.org/TR/html4/sgml/entities.html fishbowl.pastiche.org/2003/07/01/the_curse_of_apos
CMS

2
Siehe auch den Hinweis von @ kender zur schlechten Sicherheit dieses Ansatzes.
Joseph Turian

2
Siehe meine Notiz an @kender über die schlechten Tests, die er durchgeführt hat;)
Roatin Marth

24
Diese Funktion stellt ein Sicherheitsrisiko dar. JavaScript-Code wird auch dann ausgeführt, wenn das Element nicht zum DOM hinzugefügt wird. Dies ist also nur dann zu verwenden, wenn die Eingabezeichenfolge vertrauenswürdig ist. Ich habe meine eigene Antwort hinzugefügt , um das Problem zu erklären und eine sichere Lösung bereitzustellen. Als Nebeneffekt wird das Ergebnis nicht abgeschnitten, wenn mehrere Textknoten vorhanden sind.
Wladimir Palant

375

Die meisten hier gegebenen Antworten haben einen großen Nachteil: Wenn die Zeichenfolge, die Sie konvertieren möchten, nicht vertrauenswürdig ist, besteht eine XSS-Sicherheitsanfälligkeit (Cross-Site Scripting) . Beachten Sie für die Funktion in der akzeptierten Antwort Folgendes:

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

Die Zeichenfolge hier enthält ein nicht entkoppeltes HTML-Tag. Anstatt etwas zu dekodieren, führt die htmlDecodeFunktion tatsächlich den in der Zeichenfolge angegebenen JavaScript-Code aus.

Dies kann durch die Verwendung von DOMParser vermieden werden, der in allen modernen Browsern unterstützt wird :

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/)'>")  )  
// ""

Diese Funktion führt garantiert keinen JavaScript-Code als Nebeneffekt aus. Alle HTML-Tags werden ignoriert, nur Textinhalte werden zurückgegeben.

Kompatibilitätshinweis : Für das Parsen von HTML DOMParsersind mindestens Chrome 30, Firefox 12, Opera 17, Internet Explorer 10, Safari 7.1 oder Microsoft Edge erforderlich. Alle Browser ohne Unterstützung sind also weit über ihre EOL hinaus und ab 2017 sind die einzigen, die gelegentlich noch in freier Wildbahn zu sehen sind, ältere Internet Explorer- und Safari-Versionen (normalerweise sind diese noch nicht zahlreich genug, um sich darum zu kümmern).


19
Ich denke, diese Antwort ist die beste, weil sie die XSS-Sicherheitslücke erwähnt.
30онстантин Ван

2
Beachten Sie, dass (gemäß Ihrer Referenz) vor Firefox 12.0 DOMParsernicht unterstützt "text/html"wurde und es immer noch einige neueste Versionen von Browsern gibt, die dies nicht einmal unterstützenDOMParser.prototype.parseFromString() . Ihrer Referenz zufolge DOMParserhandelt es sich immer noch um eine experimentelle Technologie, und die Stellvertreter verwenden die innerHTMLEigenschaft, die, wie Sie auch als Reaktion auf meinen Ansatz hervorgehoben haben , diese XSS-Sicherheitsanfälligkeit aufweist (die von Browser-Anbietern behoben werden sollte).
PointedEars

4
@PointedEars: Wen interessiert Firefox 12 im Jahr 2016? Die problematischen sind Internet Explorer bis 9.0 und Safari bis 7.0. Wenn man es sich leisten kann, sie nicht zu unterstützen (was hoffentlich bald jeder sein wird), dann ist DOMParser die beste Wahl. Wenn nicht - ja, wäre nur die Verarbeitung von Entitäten eine Option.
Wladimir Palant

4
@PointedEars: <script>Tags, die nicht ausgeführt werden, sind kein Sicherheitsmechanismus. Diese Regel vermeidet lediglich die schwierigen Timing-Probleme, wenn durch die Einstellung innerHTMLsynchrone Skripts als Nebeneffekt ausgeführt werden könnten. Das Bereinigen von HTML-Code ist eine schwierige Angelegenheit und innerHTMLversucht es nicht einmal - bereits, weil die Webseite möglicherweise tatsächlich beabsichtigt, Inline-Ereignishandler festzulegen. Dies ist einfach kein Mechanismus für unsichere Daten, Punkt.
Wladimir Palant

1
@ ИльяЗеленько: Planen Sie, diesen Code in einer engen Schleife zu verwenden, oder warum ist die Leistung wichtig? Ihre Antwort ist wieder anfällig für XSS. War es das wirklich wert?
Wladimir Palant

37

Wenn Sie jQuery verwenden:

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

Verwenden Sie andernfalls das Encoder-Objekt von Strictly Software , das eine hervorragende htmlDecode()Funktion hat.


59
Verwenden Sie dies nicht (NICHT wiederholen) für andere vom Benutzer generierte Inhalte als die von diesem Benutzer generierten Inhalte . Wenn der Wert ein <script> -Tag enthält, wird der Inhalt des Skripts ausgeführt!
Malvolio

Ich kann dafür nirgendwo auf der Website eine Lizenz finden. Wissen Sie, was die Lizenz ist?
TRiG

Es gibt eine Lizenz im Quellheader, es ist GPL.
Chris Fulstow

6
JA, diese Funktion ebnet den Weg für XSS: Versuchen Sie es mit htmlDecode ("<script> alert (12) </ script> 123 & gt;")
Dinis Cruz

Was bedeutet das $ ('<div />') ?
Echo Yang

13

Der Trick besteht darin, die Leistung des Browsers zum Dekodieren der speziellen HTML-Zeichen zu verwenden, dem Browser jedoch nicht zu erlauben, die Ergebnisse so auszuführen, als wäre es tatsächlich HTML ... Diese Funktion verwendet einen regulären Ausdruck, um codierte HTML-Zeichen, ein Zeichen, zu identifizieren und zu ersetzen zu einer Zeit.

function unescapeHtml(html) {
    var el = document.createElement('div');
    return html.replace(/\&[#0-9a-z]+;/gi, function (enc) {
        el.innerHTML = enc;
        return el.innerText
    });
}

Die Regex kann etwas enger abgeglichen werden, /\&#?[0-9a-z]+;/gida # nur als 2. Zeichen angezeigt werden sollte, wenn überhaupt.
TheAtomicOption

Dies ist die beste Antwort. Vermeidet XSS-Sicherheitslücken und entfernt keine HTML-Tags.
Emmanuel

6

Die Antwort von CMS funktioniert einwandfrei, es sei denn, der HTML-Code, den Sie entfernen möchten, ist sehr lang und länger als 65536 Zeichen. Denn dann wird in Chrome der innere HTML-Code in viele untergeordnete Knoten aufgeteilt, von denen jeder höchstens 65536 lang ist, und Sie müssen sie verketten. Diese Funktion funktioniert auch für sehr lange Zeichenfolgen:

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;
}

innerHTMLWeitere Informationen finden Sie in dieser Antwort zur maximalen Länge: https://stackoverflow.com/a/27545633/694469


3

Keine direkte Antwort auf Ihre Frage, aber wäre es nicht besser für Ihren RPC, eine Struktur (sei es XML oder JSON oder was auch immer) mit diesen Bilddaten (URLs in Ihrem Beispiel) innerhalb dieser Struktur zurückzugeben?

Dann könnten Sie es einfach in Ihrem Javascript analysieren und das <img>mit Javascript selbst erstellen .

Die Struktur, die Sie von RPC erhalten, könnte folgendermaßen aussehen:

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

Ich denke, es ist besser so, da das Einfügen eines Codes, der von einer externen Quelle stammt, in Ihre Seite nicht sehr sicher aussieht. Stellen Sie sich vor, jemand entführt Ihr XML-RPC-Skript und fügt etwas ein, das Sie nicht möchten (sogar etwas Javascript ...).


Hat der oben genannte @ CMS-Ansatz diese Sicherheitslücke?
Joseph Turian

Ich habe gerade das folgende Argument überprüft, das an die Funktion htmlDecode übergeben wurde: htmlDecode ("& lt; img src = 'myimage.jpg' & gt; & lt; script & gt; document.write ('xxxxx'); & lt; / script & gt;") und es erstellt die <script> </ script> Element, das schlecht sein kann, imho. Und ich denke immer noch, dass es besser ist, eine Struktur anstelle von einzufügendem Text zurückzugeben. Sie können beispielsweise mit Fehlern gut umgehen.
Kender

1
Ich habe es nur versucht htmlDecode("&lt;img src='myimage.jpg'&gt;&lt;script&gt;alert('xxxxx');&lt;/script&gt;")und nichts ist passiert. Ich habe den dekodierten HTML-String wie erwartet zurückbekommen.
Roatin Marth

2

Chris Antwort ist schön und elegant aber es funktioniert nicht , wenn der Wert ist nicht definiert . Nur eine einfache Verbesserung macht es solide:

function htmlDecode(value) {
   return (typeof value === 'undefined') ? '' : $('<div/>').html(value).text();
}

Wenn Sie sich verbessern, dann tun Sie:return (typeof value !== 'string') ? '' : $('<div/>').html(value).text();
SynCap

2

Gern geschehen ... nur ein Messenger ... das volle Guthaben geht an ourcodeworld.com, Link unten.

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);
            });
        }
    };

Vollständige Gutschrift: https://ourcodeworld.com/articles/read/188/encode-and-decode-html-entities-using-pure-javascript


2

Dies ist die umfassendste Lösung, die ich bisher ausprobiert habe:

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]
        );
};

"Das umfassendste"? Haben Sie versucht, es gegen eine tatsächlich umfassende Testsuite auszuführen ?
Dan Dascalescu

1

Ich war verrückt genug, diese Funktion zu durchlaufen, die hübsch, wenn nicht vollständig, erschöpfend sein sollte:

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, "\"");
}

So verwendet:

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

Drucke: Ich Heiße David

PS: Das hat ungefähr anderthalb Stunden gedauert.


0

Um HTML-Entitäten * in JavaScript zu entfernen, können Sie die kleine Bibliothek html-escaper verwenden :npm install html-escaper

import {unescape} from 'html-escaper';

unescape('escaped string');

Oder unescapefunktionieren Sie mit Lodash oder Underscore , wenn Sie es verwenden.


*) Bitte beachten Sie, dass diese Funktionen decken nicht alle HTML - Entitäten, sondern nur die häufigsten, das heißt &, <, >, ', ". Um unescape alle HTML - Entities können Sie verwenden , er - Bibliothek.


-1

Ich verwende dies in meinem Projekt: Inspiriert von anderen Antworten, aber mit einem besonders sicheren Parameter, kann es nützlich sein, wenn Sie sich mit dekorierten Zeichen befassen

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;
    }
})();

Und es ist verwendbar wie:

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

-1

Alle anderen Antworten hier haben Probleme.

Die document.createElement ('div') -Methoden (einschließlich der Methoden, die jQuery verwenden) führen jedes übergebene Javascript aus (ein Sicherheitsproblem), und die DOMParser.parseFromString () -Methode schneidet Leerzeichen ab. Hier ist eine reine Javascript-Lösung, die kein Problem hat:

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 wird speziell verwendet, um die Ausführung von js-Code zu vermeiden. Es besteht diese:

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.

1
Nein, einen anderen Tag verwendet , funktioniert aber nicht löst das Problem. Dies ist immer noch eine XSS-Sicherheitslücke htmlDecode("</textarea><img src=x onerror=alert(1)>"). Sie haben dies gepostet, nachdem ich bereits auf dieses Problem in der Antwort von Sergio Belevskij hingewiesen habe.
Wladimir Palant

Ich kann das von Ihnen beschriebene Problem nicht reproduzieren. Ich habe Ihren Code in dieser JsFiddle und beim Ausführen wird keine Warnung angezeigt. jsfiddle.net/edsjt15g/1 Können Sie einen Blick darauf werfen? Welchen Browser verwenden Sie?
EricP

2
Ich benutze Firefox. Chrome behandelt dieses Szenario in der Tat anders, sodass der Code nicht ausgeführt wird - etwas, auf das Sie sich jedoch nicht verlassen sollten.
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);

@Wladimir Palant (Autor von AdBlock Plus) gab die DOMParser-Antwort bereits 4 Jahre zuvor. Haben Sie die vorherigen Antworten gelesen, bevor Sie Ihre veröffentlichen?
Dan Dascalescu

-7

Es gibt eine Variante, die zu 80% so produktiv ist wie die Antworten ganz oben.

Siehe den Benchmark: https://jsperf.com/decode-html12345678/1

Leistungstest

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;
}

Wenn Sie Tags hinterlassen müssen, entfernen Sie die beiden .replace(...)Aufrufe (Sie können den ersten verlassen, wenn Sie keine Skripte benötigen).


6
Herzlichen Glückwunsch, Sie haben es geschafft, die Sicherheitsanfälligkeit mit gefälschter Desinfektionslogik zu verschleiern, und das alles für einen Leistungsgewinn, der in der Praxis keine Rolle spielt. Rufen Sie decodeEntities("</textarea '><img src=x onerror=alert(1) \">")Firefox an. Bitte hören Sie auf, zu versuchen, HTML-Code mit regulären Ausdrücken zu bereinigen.
Wladimir Palant
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.