Échapper des chaînes HTML avec jQuery

609

Quelqu'un connaît-il un moyen simple d'échapper le HTML aux chaînes dans jQuery ? Je dois pouvoir passer une chaîne arbitraire et la faire correctement échapper pour l'afficher dans une page HTML (empêchant les attaques par injection JavaScript / HTML). Je suis sûr qu'il est possible d'étendre jQuery pour ce faire, mais je ne connais pas suffisamment le framework pour le moment.

Page
la source
Voir aussi perf: jsperf.com/…
Christophe Roussy

Réponses:

445

Puisque vous utilisez jQuery , vous pouvez simplement définir la textpropriété de l'élément :

// before:
// <div class="someClass">text</div>
var someHtmlString = "<script>alert('hi!');</script>";

// set a DIV's text:
$("div.someClass").text(someHtmlString);
// after: 
// <div class="someClass">&lt;script&gt;alert('hi!');&lt;/script&gt;</div>

// get the text in a string:
var escaped = $("<div>").text(someHtmlString).html();
// value: 
// &lt;script&gt;alert('hi!');&lt;/script&gt;
travis
la source
57
Vous avez manqué le point que vous devez accéder à $ ("div.someClass"). Html () pour sortir la version échappée.
Morten Christiansen
16
Ce n'est pas sûr pour tous les navigateurs si votre chaîne contient des espaces blancs et des caractères \ n \ r \ t
nivcaner
20
@travis Ceci est documenté sur le site Web jQuery: "En raison des variations des analyseurs HTML dans différents navigateurs, le texte renvoyé peut varier dans les nouvelles lignes et autres espaces blancs." api.jquery.com/text
geofflee
3
@mklement si vous utilisez déjà cette solution, vous n'avez des problèmes avec cette chose à faire comme: $(element2).attr("some-attr", $(element1).html());Voir cet exemple: jsbin.com/atibig/1/edit
TRAVIS
16
Cela n'échappe PAS aux guillemets et aux guillemets doubles, ce qui est mauvais! wonko.com/post/html-escaping
Lior
601

Il y a aussi la solution de moustache.js

var entityMap = {
  '&': '&amp;',
  '<': '&lt;',
  '>': '&gt;',
  '"': '&quot;',
  "'": '&#39;',
  '/': '&#x2F;',
  '`': '&#x60;',
  '=': '&#x3D;'
};

function escapeHtml (string) {
  return String(string).replace(/[&<>"'`=\/]/g, function (s) {
    return entityMap[s];
  });
}
Tom Gruner
la source
7
Notez que, curieusement, 'est mappé à une entité avec un format décimal , alors qu'il /utilise le format hexadécimal .
mklement0
43
Cela devrait être la réponse acceptée - elle est simple, efficace, ne nécessite aucune dépendance et fait exactement ce qui est prévu sans aucun piratage obscur.
lorefnon
6
ce qui est la direction sur la conversion \nà <br>?
amwinter
2
Voici un lien mis à jour vers la source: github.com/janl/mustache.js/blob/…
mjackson
8
@amwinter, j'ai étendu le script ci-dessus en ajoutant "\ n": '<br>' à la carte d'entité et mis à jour l'expression régulière dans / [& <> "'\ /] | [\ n] / g
walv
182
$('<div/>').text('This is fun & stuff').html(); // "This is fun &amp; stuff"

Source: http://debuggable.com/posts/encode-html-entities-with-jquery:480f4dd6-13cc-4ce9-8071-4710cbdd56cb

Henrik N
la source
11
Comme mentionné dans la réponse ci-dessus, cette solution n'est pas garantie de préserver les espaces blancs.
geofflee
47
Il faut noter que cela ne fait rien pour échapper aux guillemets simples ou doubles. si vous prévoyez de mettre la valeur dans un attribut HTML, cela peut être un problème.
Kip
6
@Kip: @travis a trouvé que la attr()méthode de jQuery (à partir d'au moins 1.8.3) fait son propre encodage, de sorte que les chaînes non encodées peuvent être passées directement ; par exemple:$('<div/>').attr('test-attr', '\'Tis "fun" & stuff')[0].outerHTML
mklement0
1
@tarekahf C'est étrange. Quelle version de jQuery utilisez-vous? L'exemple de code fonctionne-t-il si vous le copiez-collez textuellement? Fonctionne très bien avec la dernière jQuery (3.1.0) ici: jsbin.com/fazimigayo/1/edit?html,js,console,output (et cela devrait également fonctionner sur toutes les versions antérieures)
Henrik N
1
@tarekahf $('<div/>')crée un nouvel divélément qui n'est pas attaché au DOM. Cela ne changera donc aucun élément existant. C'est un peu déroutant de voir comment jQuery utilise la même $()fonction à la fois pour trouver des éléments ( $('div')) et pour les créer, et pour quelques autres choses en plus… :)
Henrik N
61

Si vous vous échappez pour HTML, il n'y en a que trois qui pourraient être vraiment nécessaires:

html.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");

En fonction de votre cas d'utilisation, vous pourriez aussi avoir besoin de faire des choses comme "à &quot;. Si la liste était suffisamment grande, j'utiliserais simplement un tableau:

var escaped = html;
var findReplace = [[/&/g, "&amp;"], [/</g, "&lt;"], [/>/g, "&gt;"], [/"/g, "&quot;"]]
for(var item in findReplace)
    escaped = escaped.replace(findReplace[item][0], findReplace[item][1]);

encodeURIComponent() n'y échappera que pour les URL, pas pour HTML.

tghw
la source
13
Cette expression régulière produira des résultats étranges si le HTML en question a déjà des entités échappées. Par exemple, échapper à "Tom & amp; Jerry" produira "Tom & amp; amp; Jerry"
Ryan
12
Veuillez utiliser varpour déclarer itemlocalement; de toute façon, n'utilisez pas for … indu tout de boucle lorsque vous parcourez un tableau! Utilisez forplutôt une boucle ordinaire . Oh, et ça ne l'est encodeURIComponentpas escapeURIComponent.
Marcel Korpel
3
Si vous travaillez avec des attributs de balise, vous devrez également échapper les guillemets et / ou les guillemets doubles. La documentation PHP pour htmlspecialchars contient une liste utile de conversions qu'elle effectue. php.net/htmlspecialchars
geofflee
4
Juste un rappel pour genre de nouvelles personnes, ne pas utiliser cette option si vous avez l' intention d'avoir des caractères non-anglais quelque part sur votre site ... Il est évident que cela ne va pas à cause des caractères accentués comme « é »: &eacute; Voici une liste d'entités html, pour référence: w3schools.com/tags/ref_entities.asp
LoganWolfer
11
@Ryan: S'il convient de souligner que cette solution ne gère pas correctement les chaînes déjà encodées, elle ne vaut rien non plus qui s'applique à la plupart - voire à toutes - les solutions de cette page.
mklement0
37

Suffisamment simple à utiliser:

_.escape(string) 

Underscore est une bibliothèque d'utilitaires qui fournit de nombreuses fonctionnalités que ne fournit pas js natif. Il y a aussi lodash qui est la même API que le trait de soulignement mais a été réécrit pour être plus performant.

chovy
la source
36

J'ai écrit une toute petite fonction qui fait ça. Il échappe seulement ", &, <et >(mais généralement ce dont vous avez besoin est de toute façon tout). Il est légèrement plus élégant que les solutions proposées précédemment en ce qu'il n'en utilise qu'une .replace() pour effectuer toute la conversion. ( EDIT 2: complexité du code réduite rendant la fonction encore plus petite et plus nette, si vous êtes curieux du code d'origine, voir la fin de cette réponse.)

function escapeHtml(text) {
    'use strict';
    return text.replace(/[\"&<>]/g, function (a) {
        return { '"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;' }[a];
    });
}

C'est du Javascript simple, pas de jQuery utilisé.

Échapper /et 'aussi

Modifier en réponse au commentaire de mklement .

La fonction ci-dessus peut facilement être étendue pour inclure n'importe quel caractère. Pour spécifier plus de caractères à échapper, insérez-les simplement dans la classe de caractères de l'expression régulière (c'est-à-dire à l'intérieur de /[...]/g) et en tant qu'entrée dans l' chrobjet. ( EDIT 2: raccourci également cette fonction, de la même manière.)

function escapeHtml(text) {
    'use strict';
    return text.replace(/[\"&'\/<>]/g, function (a) {
        return {
            '"': '&quot;', '&': '&amp;', "'": '&#39;',
            '/': '&#47;',  '<': '&lt;',  '>': '&gt;'
        }[a];
    });
}

Notez l'utilisation ci-dessus &#39;pour l'apostrophe (l'entité symbolique &apos;peut avoir été utilisée à la place - elle est définie en XML, mais n'était pas à l'origine incluse dans la spécification HTML et pourrait donc ne pas être prise en charge par tous les navigateurs. Voir: Article Wikipedia sur les encodages de caractères HTML ). Je me souviens également d'avoir lu quelque part que l'utilisation d'entités décimales est plus largement prise en charge que l'utilisation d'hexadécimal, mais je n'arrive pas à trouver la source de cela maintenant. (Et il ne peut pas y avoir beaucoup de navigateurs qui ne prennent pas en charge les entités hexadécimales.)

Remarque: L'ajout de /et 'à la liste des caractères d'échappement n'est pas très utile, car ils n'ont pas de signification particulière en HTML et n'ont pas besoin d'être échappés.

escapeHtmlFonction d' origine

EDIT 2: La fonction d'origine a utilisé une variable ( chr) pour stocker l'objet nécessaire au .replace()rappel. Cette variable avait également besoin d'une fonction anonyme supplémentaire pour l'étendre, rendant la fonction (inutilement) un peu plus grande et plus complexe.

var escapeHtml = (function () {
    'use strict';
    var chr = { '"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;' };
    return function (text) {
        return text.replace(/[\"&<>]/g, function (a) { return chr[a]; });
    };
}());

Je n'ai pas testé laquelle des deux versions est la plus rapide. Si vous le faites, n'hésitez pas à ajouter des informations et des liens à ce sujet ici.

zrajm
la source
Merci d'avoir pris le temps, @Zrajm. Bon point de ne pas avoir besoin de s'échapper; une idée pourquoi les deux mustache.jset le underscore.jsfaire? En parlant de ce dernier: il ne reconnaît que les entités numériques (représentant 'et /« ), dans l' hexagone majuscules forme quand un échapper. Ainsi, le texte s'est échappé mustache.js- qui utilise curieusement un mélange d'hex. et formats décimaux - ne serait pas correctement échappé underscore.js. Je me demande comment les autres bibliothèques populaires gèrent cela.
mklement0
1
La forme hexagonale de minuscules est la forme la plus soutenue, de sorte que est (probablement) la forme que les bibliothèques devraient convertir à . (Bien sûr, les deux formes devraient fonctionner lors de la conversion à partir de .) - Les apostrophes 'ont une sorte de fonction réservée en XML (et donc XHTML, j'imagine?), C'est pourquoi XML (mais pas HTML) a l'entité nommée &apos;. Je ne sais pas exactement pourquoi ni de quelle manière il est «réservé». - Les barres obliques sont spéciaux dans les URL, mais cela ne fait les justifient l'inscription à échapper à HTML (comme URL encodage est quelque chose de complètement différent).
zrajm
Re &apos;: correct: utilisation sûre uniquement en XHTML ; directement à partir de la bouche de la foule - accentuation du mien: "(...) lu par un processeur HTML conforme , (...) l'utilisation de & apos; ou des références d'entité personnalisées peuvent ne pas être prises en charge (...)" - en pratique : les navigateurs modernes le supportent même en HTML . Re cas en nombres hexadécimaux. (même source; c'est moi qui souligne): "Le x doit être en minuscules dans les documents XML. […] Le hhhh peut mélanger majuscules et minuscules, bien que les majuscules soient le style habituel ." Nous laisse nous demander qui a décidé d'encoder les barres obliques; peut-être vraiment juste une confusion entre l'URI et le codage HTML?
mklement0
2
Réflexions finales: il semble que l'encodage /ne soit pas nécessaire, mais l'encodage 'semble toujours utile pour gérer en toute sécurité le cas où une chaîne codée est utilisée comme valeur d' attribut entre guillemets simples .
mklement0
Ces deux éléments sont lents. La solution la plus rapide par une marge à deux chiffres est une série de remplacements auxquels sont passées des chaînes au lieu de fonctions.
Adam Leggett
34

Je me rends compte à quel point je suis en retard à cette fête, mais j'ai une solution très simple qui ne nécessite pas jQuery.

escaped = new Option(unescaped).innerHTML;

Edit: Cela n'échappe pas aux guillemets. Le seul cas où les guillemets devraient être échappés est si le contenu doit être collé en ligne dans un attribut dans une chaîne HTML. Il m'est difficile d'imaginer un cas où cela serait une bonne conception.

Edit 3: Pour la solution la plus rapide, vérifiez la réponse ci-dessus de Saram. Celui-ci est le plus court.

Adam Leggett
la source
Cela ne change pas les devis - au moins en ce moment dans Firefox 52.
getsetbro
1
Les guillemets d'échappement ne sont pertinents que sur le plan fonctionnel dans les attributs. Puisque nous nous échappons <et >, il n'y a aucun avantage à échapper les guillemets également, à moins que l'intention du contenu généré ne soit d'aller dans un attribut.
Adam Leggett
31

Voici une fonction JavaScript claire et claire. Il échappera du texte tel que "quelques <plusieurs" à "quelques-uns & lt; plusieurs".

function escapeHtmlEntities (str) {
  if (typeof jQuery !== 'undefined') {
    // Create an empty div to use as a container,
    // then put the raw text in and get the HTML
    // equivalent out.
    return jQuery('<div/>').text(str).html();
  }

  // No jQuery, so use string replace.
  return str
    .replace(/&/g, '&amp;')
    .replace(/>/g, '&gt;')
    .replace(/</g, '&lt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&apos;');
}
intrepidis
la source
28

Après les derniers tests, je peux recommander une solution javaScript native (DOM) native la plus rapide et entièrement compatible avec les navigateurs :

function HTMLescape(html){
    return document.createElement('div')
        .appendChild(document.createTextNode(html))
        .parentNode
        .innerHTML
}

Si vous le répétez plusieurs fois, vous pouvez le faire avec des variables une fois préparées:

//prepare variables
var DOMtext = document.createTextNode("test");
var DOMnative = document.createElement("span");
DOMnative.appendChild(DOMtext);

//main work for each case
function HTMLescape(html){
  DOMtext.nodeValue = html;
  return DOMnative.innerHTML
}

Regardez ma comparaison finale de performance ( question de pile ).

Saram
la source
2
Faut-il utiliser deux nœuds? Que diriez-vous d'un seul:var p = document.createElement('p'); p.textContent = html; return p.innerHTML;
Dan Dascalescu
2
@DanDascalescu: Selon MDN , la textContentfonction n'est prise en charge que par Chrome 1+, Firefox 2, IE9, Opera 9.64 et Safari 3 (ces deux derniers annotés "peut-être plus tôt"). Cela briserait ainsi la revendication "totalement compatible avec tous les navigateurs" des PO.
zb226
p.innerText = html; return p.innerHTML
Bekim Bacaj
24

Essayez la bibliothèque Underscore.string , cela fonctionne avec jQuery.

_.str.escapeHTML('<div>Blah blah blah</div>')

production:

'&lt;div&gt;Blah blah blah&lt;/div&gt;'
Nikita Koksharov
la source
20
La bibliothèque principale de soulignement possède désormais une _.escape()fonction utilitaire.
codeape
15

J'ai amélioré l'exemple mustache.js en ajoutant la escapeHTML()méthode à l'objet chaîne.

var __entityMap = {
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    '"': '&quot;',
    "'": '&#39;',
    "/": '&#x2F;'
};

String.prototype.escapeHTML = function() {
    return String(this).replace(/[&<>"'\/]/g, function (s) {
        return __entityMap[s];
    });
}

De cette façon, il est assez facile à utiliser "Some <text>, more Text&Text".escapeHTML()

Jeena
la source
Utile, mais aussi je suis passé __entityMapà la portée locale de la fonction. Et enveloppé tout cela dansif (typeof String.prototype.escapeHTML !== 'function'){...}
FlameStorm
15

escape()et unescape()sont destinés à encoder / décoder des chaînes pour les URL, pas HTML.

En fait, j'utilise l'extrait de code suivant pour faire l'astuce qui ne nécessite aucun cadre:

var escapedHtml = html.replace(/&/g, '&amp;')
                      .replace(/>/g, '&gt;')
                      .replace(/</g, '&lt;')
                      .replace(/"/g, '&quot;')
                      .replace(/'/g, '&apos;');
NicolasBernier
la source
Si vous allez avoir des "s, vous devez ajouter au moins 'et `` à la mêlée. Ceux-ci ne sont vraiment nécessaires que pour les données de balises de chaîne à l'intérieur des éléments en html. Pour les données html elles-mêmes (hors balises), seuls les 3 premiers sont requis.
Marius
10

Si vous avez underscore.js, utilisez _.escape(plus efficace que la méthode jQuery publiée ci-dessus):

_.escape('Curly, Larry & Moe'); // returns: Curly, Larry &amp; Moe
ronnbot
la source
5

Si vous suivez la route des expressions rationnelles, il y a une erreur dans l'exemple de tghw ci-dessus.

<!-- WON'T WORK -  item[0] is an index, not an item -->

var escaped = html; 
var findReplace = [[/&/g, "&amp;"], [/</g, "&lt;"], [/>/g,"&gt;"], [/"/g,
"&quot;"]]

for(var item in findReplace) {
     escaped = escaped.replace(item[0], item[1]);   
}


<!-- WORKS - findReplace[item[]] correctly references contents -->

var escaped = html;
var findReplace = [[/&/g, "&amp;"], [/</g, "&lt;"], [/>/g, "&gt;"], [/"/g, "&quot;"]]

for(var item in findReplace) {
     escaped = escaped.replace(findReplace[item[0]], findReplace[item[1]]);
}
Wayne
la source
2
Je crois que cela devrait être pour (var item dans findReplace) {escaped = escaped.replace (findReplace [item] [0], findReplace [item] [1]); }
Chris Stephens
5

Ceci est un bel exemple sûr ...

function escapeHtml(str) {
    if (typeof(str) == "string"){
        try{
            var newStr = "";
            var nextCode = 0;
            for (var i = 0;i < str.length;i++){
                nextCode = str.charCodeAt(i);
                if (nextCode > 0 && nextCode < 128){
                    newStr += "&#"+nextCode+";";
                }
                else{
                    newStr += "?";
                }
             }
             return newStr;
        }
        catch(err){
        }
    }
    else{
        return str;
    }
}
amrp
la source
4
Quels types d'exceptions supprimez-vous là-bas?
Stefan Majewsky
3

Vous pouvez facilement le faire avec vanilla js.

Ajoutez simplement un nœud de texte au document. Il sera échappé par le navigateur.

var escaped = document.createTextNode("<HTML TO/ESCAPE/>")
document.getElementById("[PARENT_NODE]").appendChild(escaped)
raam86
la source
2
(function(undefined){
    var charsToReplace = {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;'
    };

    var replaceReg = new RegExp("[" + Object.keys(charsToReplace).join("") + "]", "g");
    var replaceFn = function(tag){ return charsToReplace[tag] || tag; };

    var replaceRegF = function(replaceMap) {
        return (new RegExp("[" + Object.keys(charsToReplace).concat(Object.keys(replaceMap)).join("") + "]", "gi"));
    };
    var replaceFnF = function(replaceMap) {
        return function(tag){ return replaceMap[tag] || charsToReplace[tag] || tag; };
    };

    String.prototype.htmlEscape = function(replaceMap) {
        if (replaceMap === undefined) return this.replace(replaceReg, replaceFn);
        return this.replace(replaceRegF(replaceMap), replaceFnF(replaceMap));
    };
})();

Aucune variable globale, une certaine optimisation de la mémoire. Usage:

"some<tag>and&symbol©".htmlEscape({'©': '&copy;'})

le résultat est:

"some&lt;tag&gt;and&amp;symbol&copy;"
Gheljenor
la source
2

2 méthodes simples qui ne nécessitent AUCUN JQUERY ...

Vous pouvez encoder tous les caractères de votre chaîne comme ceci:

function encode(e){return e.replace(/[^]/g,function(e){return"&#"+e.charCodeAt(0)+";"})}

Ou tout simplement cibler les personnages principaux à se soucier &, les sauts de ligne, <, >, "et 'comme:

function encode(r){
return r.replace(/[\x26\x0A\<>'"]/g,function(r){return"&#"+r.charCodeAt(0)+";"})
}

var myString='Encode HTML entities!\n"Safe" escape <script></'+'script> & other tags!';

test.value=encode(myString);

testing.innerHTML=encode(myString);

/*************
* \x26 is &ampersand (it has to be first),
* \x0A is newline,
*************/
<p><b>What JavaScript Generated:</b></p>

<textarea id=test rows="3" cols="55"></textarea>

<p><b>What It Renders Too In HTML:</b></p>

<div id="testing">www.WHAK.com</div>

Dave Brown
la source
2

Exemple d'échappement JavaScript simple:

function escapeHtml(text) {
    var div = document.createElement('div');
    div.innerText = text;
    return div.innerHTML;
}

escapeHtml("<script>alert('hi!');</script>")
// "&lt;script&gt;alert('hi!');&lt;/script&gt;"
Andrew Luca
la source
3
Les réponses uniquement codées sont déconseillées car elles n'expliquent pas comment elles résolvent le problème. Veuillez mettre à jour votre réponse pour expliquer comment cela améliore les autres réponses acceptées et votées que cette question a déjà. De plus, cette question a 9 ans, vos efforts seraient plus appréciés par les utilisateurs qui ont des questions sans réponse récentes. Veuillez consulter Comment écrire une bonne réponse .
FluffyKitten
1
@FluffyKitten est un article de blog extrêmement bien écrit sur les avantages et les inconvénients d'une telle fonction qui explique en détail tout ce que vous aimeriez savoir :) shebang.brandonmintern.com/…
db306
@ db306 La réponse a été signalée comme de faible qualité car la réponse en code uniquement ne répond pas aux directives de dépassement de pile - voir Comment écrire une bonne réponse . Mon commentaire a été ajouté au cours du processus de révision pour expliquer ce qui est nécessaire pour l'améliorer, c'est-à-dire que la réponse doit être mise à jour pour expliquer ce que fait le code et comment il améliore les réponses existantes. Les votes positifs sont d'autres critiques pour approuver cela. L'ajout d'un lien externe aux commentaires ne répond toujours pas aux directives SO. Au lieu de cela, Andrew doit inclure les informations pertinentes directement dans sa réponse.
FluffyKitten
Notez que brandonmintern DOT com a expiré et est maintenant parqué. La nouvelle adresse shebang est shebang.mintern.net/foolproof-html-escaping-in-javascript/.
Brandon
0
function htmlEscape(str) {
    var stringval="";
    $.each(str, function (i, element) {
        alert(element);
        stringval += element
            .replace(/&/g, '&amp;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#39;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(' ', '-')
            .replace('?', '-')
            .replace(':', '-')
            .replace('|', '-')
            .replace('.', '-');
    });
    alert(stringval);
    return String(stringval);
}
Katharapu Ramana
la source
0
function htmlDecode(t){
   if (t) return $('<div />').html(t).text();
}

fonctionne comme un charme

d -_- b
la source
le texte supprime les balises html, mais $ ('<div />'). html (t) .html (); oeuvres
Bass Jobsen
0

Cette réponse fournit les méthodes jQuery et JS normales, mais c'est la plus courte sans utiliser le DOM:

unescape(escape("It's > 20% less complicated this way."))

Chaîne échappée: It%27s%20%3E%2020%25%20less%20complicated%20this%20way.

Si les espaces échappés vous dérangent, essayez:

unescape(escape("It's > 20% less complicated this way.").replace(/%20/g, " "))

Chaîne échappée: It%27s %3E 20%25 less complicated this way.

Malheureusement, la escape()fonction était obsolète dans JavaScript version 1.5 . encodeURI()ou encodeURIComponent()sont des alternatives, mais ils ignorent ', donc la dernière ligne de code se transformerait en ceci:

decodeURI(encodeURI("It's > 20% less complicated this way.").replace(/%20/g, " ").replace("'", '%27'))

Tous les principaux navigateurs prennent toujours en charge le code court, et compte tenu du nombre d'anciens sites Web, je doute que cela changera bientôt.

Cees Timmerman
la source
C'est pour le codage d'URL. La question portait sur l'échappement HTML, ce qui est très différent.
thelem
@thelem, pas si les chaînes sont incorporées dans des tableaux JavaScript incorporés dans HTML, mais je suis d'accord qu'il s'agissait d'un échappement HTML simple afin qu'il puisse être immédiatement affiché sous forme de texte.
Cees Timmerman du
0

ES6 un liner pour la solution de moustache.js

const escapeHTML = str => (str+'').replace(/[&<>"'`=\/]/g, s => ({'&': '&amp;','<': '&lt;','>': '&gt;','"': '&quot;',"'": '&#39;','/': '&#x2F;','`': '&#x60;','=': '&#x3D;'})[s]);
poulets
la source
-2

Si vous enregistrez ces informations dans une base de données , il est incorrect d'échapper au HTML à l'aide d'un script côté client , cela doit être fait sur le serveur . Sinon, il est facile de contourner votre protection XSS.

Pour clarifier mon propos, voici un exemple utilisant l'une des réponses:

Supposons que vous utilisez la fonction escapeHtml pour échapper le HTML d'un commentaire dans votre blog, puis le publier sur votre serveur.

var entityMap = {
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    '"': '&quot;',
    "'": '&#39;',
    "/": '&#x2F;'
  };

  function escapeHtml(string) {
    return String(string).replace(/[&<>"'\/]/g, function (s) {
      return entityMap[s];
    });
  }

L'utilisateur pourrait:

  • Modifiez les paramètres de la requête POST et remplacez le commentaire par du code javascript.
  • Remplacez la fonction escapeHtml à l'aide de la console du navigateur.

Si l'utilisateur colle cet extrait dans la console, il contourne la validation XSS:

function escapeHtml(string){
   return string
}
Kauê Gimenes
la source
Je ne suis pas d'accord. Pour contourner cette protection XSS, vous devez utiliser une attaque XSS (injecter un script qui désactive l'échappement), ce que vous bloquez réellement. Dans certains cas, il est en fait plus approprié de s'échapper sur le client, par exemple si les données proviennent d'une API REST qui doit renvoyer du JSON standard.
ItalyPaleAle
@Qualcuno Si vous effectuez cette validation dans le client et que vous postez ces informations sur le serveur en vous assurant qu'elles ont été validées, l'utilisateur peut simplement modifier la demande et le script sera enregistré dans la base de données.
Kauê Gimenes
@Qualcuno J'ai inclus quelques exemples pour clarifier mon propos.
Kauê Gimenes
1
La question portait sur l'échappement des chaînes reçues du serveur pour les afficher sur le navigateur. Ce que vous dites, c'est d'échapper aux chaînes avant de les soumettre au serveur, ce qui est différent (bien que vous ayez raison, là-bas, et cela revient à l'ancienne règle, n'acceptez jamais aveuglément aucune entrée du client )
ItalyPaleAle
@Qualcuno C'est une question populaire dans Stackoverflow, et je pense que c'est un point important à couvrir. C'est pourquoi j'ai répondu.
Kauê Gimenes
-2

Toutes les solutions sont inutiles si vous ne re-fuite empêcher, par exemple la plupart des solutions garderaient échapper &à &amp;.

escapeHtml = function (s) {
    return s ? s.replace(
        /[&<>'"]/g,
        function (c, offset, str) {
            if (c === "&") {
                var substr = str.substring(offset, offset + 6);
                if (/&(amp|lt|gt|apos|quot);/.test(substr)) {
                    // already escaped, do not re-escape
                    return c;
                }
            }
            return "&" + {
                "&": "amp",
                "<": "lt",
                ">": "gt",
                "'": "apos",
                '"': "quot"
            }[c] + ";";
        }
    ) : "";
};
C Nimmanant
la source
4
Cela s'appelle un double échappement et devrait être corrigé en s'assurant que vos données d'entrée ne sont pas déjà échappées. Et si vous vouliez littéralement montrer & lt; à l'utilisateur? Ou peut-être que le texte va être réutilisé ailleurs et dépendra de la fuite qui s'est produite?
thelem