Unescape HTML entités en Javascript?


176

J'ai du code Javascript qui communique avec un backend XML-RPC. Le XML-RPC renvoie des chaînes de la forme:

<img src='myimage.jpg'>

Cependant, lorsque j'utilise le Javascript pour insérer les chaînes dans HTML, elles sont rendues littéralement. Je ne vois pas d'image, je vois littéralement la chaîne:

<img src='myimage.jpg'>

Je suppose que le HTML est échappé via le canal XML-RPC.

Comment puis-je échapper à la chaîne en Javascript? J'ai essayé les techniques de cette page, sans succès: http://paulschreiber.com/blog/2008/09/20/javascript-how-to-unescape-html-entities/

Quels sont les autres moyens de diagnostiquer le problème?



Réponses:


176

EDIT: Vous devriez utiliser l'API DOMParser comme le suggère Wladimir , j'ai édité ma réponse précédente car la fonction publiée a introduit une faille de sécurité.

L'extrait suivant est l'ancien code de la réponse avec une petite modification: l'utilisation de a textareaau lieu de a divréduit la vulnérabilité XSS, mais elle est toujours problématique dans IE9 et 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'>"

Fondamentalement, je crée un élément DOM par programme, assigne le HTML encodé à son innerHTML et récupère le nodeValue à partir du nœud de texte créé lors de l'insertion innerHTML. Puisqu'il crée simplement un élément mais ne l'ajoute jamais, aucun code HTML de site n'est modifié.

Il fonctionnera sur plusieurs navigateurs (y compris les anciens navigateurs) et acceptera toutes les entités de caractères HTML .

EDIT: L'ancienne version de ce code ne fonctionnait pas sur IE avec des entrées vides, comme en témoigne ici jsFiddle (vue dans IE). La version ci-dessus fonctionne avec toutes les entrées.

MISE À JOUR: semble que cela ne fonctionne pas avec une grande chaîne, et cela introduit également une vulnérabilité de sécurité , voir les commentaires.


OK, vous avez changé en ', alors laissez-moi supprimer mon commentaire en arrière, merci, ça marche très bien, +1
VOUS

1
@ S.Mark: &apos;n'appartient pas aux entités HTML 4, c'est pourquoi! w3.org/TR/html4/sgml/entities.html fishbowl.pastiche.org/2003/07/01/the_curse_of_apos
CMS

2
Voir aussi la note de @ kender sur la faible sécurité de cette approche.
Joseph Turian

2
Voir ma note à @kender sur les mauvais tests qu'il a effectués;)
Roatin Marth

24
Cette fonction est un danger pour la sécurité, le code JavaScript fonctionnera même si l'élément n'est pas ajouté au DOM. Ce n'est donc quelque chose à utiliser si la chaîne d'entrée est approuvée. J'ai ajouté ma propre réponse expliquant le problème et fournissant une solution sécurisée. En tant qu'effet secondaire, le résultat n'est pas coupé s'il existe plusieurs nœuds de texte.
Wladimir Palant

376

La plupart des réponses données ici ont un énorme inconvénient: si la chaîne que vous essayez de convertir n'est pas fiable, vous vous retrouverez avec une vulnérabilité de Cross-Site Scripting (XSS) . Pour la fonction dans la réponse acceptée, tenez compte de ce qui suit:

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

La chaîne ici contient une balise HTML sans échappement, donc au lieu de décoder quoi que ce soit, la htmlDecodefonction exécutera en fait le code JavaScript spécifié dans la chaîne.

Cela peut être évité en utilisant DOMParser qui est pris en charge dans tous les navigateurs modernes :

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

Il est garanti que cette fonction n'exécute aucun code JavaScript comme effet secondaire. Toutes les balises HTML seront ignorées, seul le contenu textuel sera renvoyé.

Note de compatibilité : L'analyse HTML avec DOMParsernécessite au moins Chrome 30, Firefox 12, Opera 17, Internet Explorer 10, Safari 7.1 ou Microsoft Edge. Ainsi, tous les navigateurs sans support ont bien dépassé leur fin de vie et à partir de 2017, les seuls qui peuvent encore être vus dans la nature sont les anciennes versions d'Internet Explorer et de Safari (généralement, elles ne sont toujours pas assez nombreuses pour déranger).


19
Je pense que cette réponse est la meilleure car elle mentionnait la vulnérabilité XSS.
Константин Ван

2
Notez que (selon votre référence) DOMParserne prenait pas en charge "text/html"avant Firefox 12.0, et il existe encore certaines dernières versions de navigateurs qui ne prennent même pas en chargeDOMParser.prototype.parseFromString() . Selon votre référence, il DOMParsers'agit toujours d'une technologie expérimentale, et les remplaçants utilisent la innerHTMLpropriété qui, comme vous l'avez également souligné en réponse à mon approche , présente cette vulnérabilité XSS (qui devrait être corrigée par les fournisseurs de navigateurs).
PointedEars

4
@PointedEars: Qui se soucie de Firefox 12 en 2016? Les plus problématiques sont Internet Explorer jusqu'à 9.0 et Safari jusqu'à 7.0. Si l'on peut se permettre de ne pas les soutenir (ce qui, espérons-le, sera tout le monde bientôt), alors DOMParser est le meilleur choix. Si non - oui, traiter uniquement les entités serait une option.
Wladimir Palant

4
@PointedEars: les <script>balises non exécutées ne sont pas un mécanisme de sécurité, cette règle évite simplement les problèmes de synchronisation délicats si le paramétrage innerHTMLpouvait exécuter des scripts synchrones en tant qu'effet secondaire. La désinfection du code HTML est une affaire délicate et innerHTMLn'essaye même pas - déjà parce que la page Web pourrait en fait avoir l'intention de définir des gestionnaires d'événements en ligne. Ce n'est tout simplement pas un mécanisme destiné aux données dangereuses, point final.
Wladimir Palant

1
@ ИльяЗеленько: Avez-vous l'intention d'utiliser ce code dans une boucle serrée ou pourquoi les performances sont-elles importantes? Votre réponse est à nouveau vulnérable à XSS, cela en valait-il vraiment la peine?
Wladimir Palant

37

Si vous utilisez jQuery:

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

Sinon, utilisez l'objet Encoder de Strictly Software , qui a une excellente htmlDecode()fonction.


59
N'utilisez pas (ne répétez PAS) ceci pour le contenu généré par l' utilisateur autre que le contenu généré par cet utilisateur. S'il y a une balise <script> dans la valeur, le contenu du script sera exécuté!
Malvolio

Je ne trouve pas de licence pour cela sur le site. Savez-vous ce qu'est la licence?
TRiG

Il y a une licence dans l'en-tête source, c'est GPL.
Chris Fulstow

6
OUI, cette fonction ouvre la voie à XSS: essayez htmlDecode ("<script> alert (12) </script> 123 & gt;")
Dinis Cruz

quelle est la signification de $ ('<div />') ?
Echo Yang

13

L'astuce consiste à utiliser la puissance du navigateur pour décoder les caractères HTML spéciaux, mais pas à permettre au navigateur d'exécuter les résultats comme s'il s'agissait de véritables html ... Cette fonction utilise une expression régulière pour identifier et remplacer les caractères HTML encodés, un caractère à la fois.

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

L'expression régulière peut être assortie un peu plus étroitement /\&#?[0-9a-z]+;/gipuisque # ne devrait apparaître que comme le deuxième caractère, voire pas du tout.
TheAtomicOption

C'est la meilleure réponse. Évite la vulnérabilité XSS et ne supprime pas les balises HTML.
Emmanuel

6

La réponse de CMS fonctionne bien, à moins que le code HTML que vous voulez ne pas échapper soit très long, plus de 65 536 caractères. Parce que dans Chrome, le HTML interne est divisé en plusieurs nœuds enfants, chacun d'au plus 65536 de long, et vous devez les concaténer. Cette fonction fonctionne également pour les très longues chaînes:

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

Voir cette réponse sur innerHTMLla longueur maximale pour plus d'informations: https://stackoverflow.com/a/27545633/694469


3

Pas une réponse directe à votre question, mais ne serait-il pas préférable que votre RPC renvoie une structure (que ce soit XML ou JSON ou autre) avec ces données d'image (URL dans votre exemple) à l'intérieur de cette structure?

Ensuite, vous pouvez simplement l'analyser dans votre javascript et créer le <img>javascript lui-même.

La structure que vous recevez de RPC pourrait ressembler à:

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

Je pense que c'est mieux ainsi, car l'injection d'un code provenant d'une source externe dans votre page ne semble pas très sécurisée. Créer une image de quelqu'un qui pirate votre script XML-RPC et y mettre quelque chose que vous ne voudriez pas (même du javascript ...)


L'approche @CMS ci-dessus présente-t-elle cette faille de sécurité?
Joseph Turian

Je viens de vérifier l'argument suivant passé à la fonction htmlDecode: htmlDecode ("& lt; img src = 'myimage.jpg' & gt; & lt; script & gt; document.write ('xxxxx'); & lt; / script & gt;") et il crée le <script> </script> élément qui peut être mauvais, à mon humble avis. Et je pense toujours que retourner une structure au lieu du texte à insérer est préférable, vous pouvez bien gérer les erreurs par exemple.
kender

1
J'ai juste essayé htmlDecode("&lt;img src='myimage.jpg'&gt;&lt;script&gt;alert('xxxxx');&lt;/script&gt;")et rien ne s'est passé. J'ai récupéré la chaîne html décodée comme prévu.
Roatin Marth

2

La réponse de Chris est belle et élégante mais elle échoue si la valeur n'est pas définie . Une simple amélioration le rend solide:

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

Si vous améliorez, faites:return (typeof value !== 'string') ? '' : $('<div/>').html(value).text();
SynCap

2

Vous êtes le bienvenu ... juste un messager ... tout le mérite revient à ourcodeworld.com, lien ci-dessous.

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

Crédit complet: https://ourcodeworld.com/articles/read/188/encode-and-decode-html-entities-using-pure-javascript


2

C'est la solution la plus complète que j'ai essayée jusqu'à présent:

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

"Le plus complet"? Avez-vous essayé de l'exécuter sur une suite de tests réellement complète ?
Dan Dascalescu

1

J'étais assez fou pour passer en revue et faire cette fonction qui devrait être jolie, sinon complètement, exhaustive:

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

Utilisé comme ça:

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

Impressions: Ich Heiße David

PS cela a pris environ une heure et demie à faire.


0

Pour échapper aux entités HTML * en JavaScript, vous pouvez utiliser la petite bibliothèque html-escaper :npm install html-escaper

import {unescape} from 'html-escaper';

unescape('escaped string');

Ou unescapefonction de Lodash ou Underscore , si vous l'utilisez.


*) S'il vous plaît noter que ces fonctions ne couvrent pas toutes les entités HTML, mais seulement, à savoir les plus communs &, <, >, ', ". Pour Unescape toutes les entités HTML , vous pouvez utiliser il bibliothèque.


-1

J'utilise ceci dans mon projet: inspiré par d' autres réponses mais avec un paramètre supplémentaire sécurisé, peut être utile lorsque vous traitez avec des personnages décorés

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

Et c'est utilisable comme:

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

-1

Toutes les autres réponses ici ont des problèmes.

Les méthodes document.createElement ('div') (y compris celles utilisant jQuery) exécutent tout javascript qui y est passé (un problème de sécurité) et la méthode DOMParser.parseFromString () supprime les espaces. Voici une solution javascript pure qui n'a aucun problème:

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 est utilisé spécifiquement pour éviter d'exécuter le code js. Il passe ceux-ci:

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
Non, l'utilisation d'une balise différente ne résout pas le problème. Il s'agit toujours d'une vulnérabilité XSS, essayez htmlDecode("</textarea><img src=x onerror=alert(1)>"). Vous avez posté ceci après avoir déjà signalé ce problème sur la réponse de Sergio Belevskij.
Wladimir Palant

Je ne parviens pas à reproduire le problème que vous décrivez. J'ai votre code dans ce JsFiddle, et aucune alerte ne s'affiche lors de l'exécution. jsfiddle.net/edsjt15g/1 Pouvez-vous jeter un oeil? Quel navigateur utilisez-vous?
EricP

2
J'utilise Firefox. Chrome gère en effet ce scénario différemment, de sorte que le code ne s'exécute pas - pas quelque chose sur lequel vous devriez vous fier cependant.
Wladimir Palant le

-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 (auteur d'AdBlock Plus) a déjà donné la réponse DOMParser 4 ans plus tôt. Avez-vous lu les réponses précédentes avant de publier les vôtres?
Dan Dascalescu

-7

Il existe une variante 80% aussi productive que les réponses tout en haut.

Voir le benchmark: https://jsperf.com/decode-html12345678/1

test de performance

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

Si vous devez laisser des balises, supprimez les deux .replace(...)appels (vous pouvez laisser le premier si vous n'avez pas besoin de scripts).


6
Félicitations, vous avez réussi à obscurcir la vulnérabilité avec une fausse logique de désinfection, le tout pour une performance gagnante qui n'aura pas d'importance en pratique. Essayez d'appeler decodeEntities("</textarea '><img src=x onerror=alert(1) \">")dans Firefox. Veuillez arrêter d'essayer de nettoyer le code HTML avec des expressions régulières.
Wladimir Palant
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.