Échapper aux chaînes HTML avec jQuery

est-ce que quelqu'un connaît un moyen facile d'échapper au HTML des cordes dans jQuery ? J'ai besoin d'être capable de passer une chaîne de caractères arbitraire et de l'avoir correctement échappée pour l'affichage dans une page HTML (empêchant les attaques par injection JavaScript/HTML). Je suis sûr qu'il est possible d'étendre jQuery pour faire cela, mais je ne sais pas assez sur le cadre au moment de l'accomplir.

550
demandé sur Matt Fenwick 2008-08-24 06:52:42

24 réponses

puisque vous utilisez jQuery , vous pouvez simplement définir l'élément text propriété:

// 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;
399
répondu travis 2018-04-07 10:09:33

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];
  });
}
538
répondu Tom Gruner 2017-01-13 19:14:50
$('<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

176
répondu Henrik N 2011-08-25 22:36:06

si vous vous échappez pour HTML, il n'y en a que trois que je peux imaginer qui seraient vraiment nécessaires:

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

Selon votre cas d'utilisation, vous pourriez aussi avoir besoin de faire des choses comme " à &quot; . Si la liste était assez grande, j'utiliserais juste 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 URLs, pas pour HTML.

58
répondu tghw 2016-02-08 14:18:19

j'ai écrit une petite fonction qui fait cela. Il s'échappe seulement " , & , < et > (mais habituellement c'est tout ce dont vous avez besoin de toute façon). Il est légèrement plus élégant que les solutions proposées précédemment en ce qu'il utilise seulement un "1519210920 .replace() pour faire toute la conversion. ( EDIT 2: code de Réduction de la complexité de prise de fonction encore plus petit et plus propre, si vous êtes curieux de connaître le 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 pur, pas de jQuery utilisé.

escapade / et ' too

Modifier en réponse à mklement 's commentaire.

La fonction ci-dessus peut facilement être étendue pour inclure n'importe quel caractère. Pour spécifier plus de caractères à escape, il suffit de les insérer tous les deux dans la classe de caractères dans la régulière expression (i.e. inside the /[...]/g ) et comme une entrée dans l'objet chr . ( EDIT 2: raccourcit cette fonction aussi, 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 de &#39; pour apostrophe (l'entité symbolique &apos; aurait pu être 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 HTML codages de caractères ). Je me souviens aussi avoir lu quelque part que l'utilisation d'entités décimales est plus largement supportée que l'utilisation d'hexadécimal, mais je ne semble pas trouver la source pour cela maintenant. (Et il ne peut pas y avoir beaucoup de navigateurs qui ne prennent pas en charge les entités hexadécimales.)

Note: ajouter / et ' à la liste des caractères échappés n'est pas très utile, car ils n'ont pas de ce qui signifie en HTML et ne pas besoin pour être échappé.

Original escapeHtml Fonction

EDIT 2: La fonction d'origine utilisé une variable ( chr ) pour stocker les objets nécessaires à la .replace() de rappel. Cette variable avait également besoin d'une fonction anonyme supplémentaire pour la visualiser, ce qui rendait 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 sont plus rapides. Si vous le faites, n'hésitez pas à ajouter des informations et des liens à ce sujet ici.

35
répondu zrajm 2015-08-19 15:03:50

assez facile à utiliser underscore:

_.escape(string) 

Underscore est une bibliothèque utilitaire qui fournit beaucoup de fonctionnalités que JS native ne fournit pas. Il y a aussi lodash qui est la même API que underscore mais qui a été réécrite pour être plus performant.

32
répondu chovy 2015-09-02 06:05:04

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

escaped = new Option(unescaped).innerHTML;

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

Edit 2: si la performance est cruciale, la plus haute performance solution (environ 50%) est encore une série de regex remplace. Les navigateurs modernes détecteront que les expressions régulières ne contiennent aucun opérateur, juste une chaîne de caractères, et les effondreront toutes en une seule opération.

30
répondu Adam Leggett 2017-06-08 20:28:27

Voici une fonction JavaScript propre et claire. Il échappera à des textes tels que "quelques-uns < beaucoup" en "quelques-uns < beaucoup".

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;');
}
26
répondu intrepidis 2018-04-20 17:56:57

Essayer Trait De Soulignement.string lib, il fonctionne avec jQuery.

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

sortie:

'&lt;div&gt;Blah blah blah&lt;/div&gt;'
24
répondu Nikita Koksharov 2012-08-20 07:36:13

après les derniers tests je peux recommander le plus rapide et complètement cross browser compatible JavaScript natif (DOM) solution:

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 préparées une fois:

//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 mon dernier spectacle comparaison ( "1519150920 pile" question ).

23
répondu Saram 2018-04-07 10:54:05

j'ai amélioré la moustache.js exemple ajouter la méthode escapeHTML() à l'objet string.

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

15
répondu Jeena 2012-11-22 10:20:19

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

en fait, j'utilise l'extrait suivant pour faire le tour qui ne nécessite pas de cadre:

var escapedHtml = html.replace(/&/g, '&amp;')
                      .replace(/>/g, '&gt;')
                      .replace(/</g, '&lt;')
                      .replace(/"/g, '&quot;')
                      .replace(/'/g, '&apos;');
15
répondu NicolasBernier 2016-02-08 14:19:01

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

_.escape('Curly, Larry & Moe'); // returns: Curly, Larry &amp; Moe
10
répondu ronnbot 2016-02-08 14:16:18

si vous suivez la route regex, 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]]);
}
5
répondu Wayne 2011-05-21 21:18:27

c'est un bel exemple de sécurité...

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;
    }
}
4
répondu amrp 2012-10-31 01:31:02

vous pouvez facilement le faire avec vanilla js.

il suffit d'ajouter un noeud de texte le document. Il sera remplacé par le navigateur.

var escaped = document.createTextNode("<HTML TO/ESCAPE/>")
document.getElementById("[PARENT_NODE]").appendChild(escaped)
3
répondu raam86 2015-01-29 16:34:02
(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));
    };
})();

pas de variables globales, optimisation de la mémoire. Usage:

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

résultat:

"some&lt;tag&gt;and&amp;symbol&copy;"
2
répondu Gheljenor 2013-05-13 11:21:59
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);
}
1
répondu Katharapu Ramana 2013-05-29 08:01:35

2 méthodes simples qui ne nécessitent pas de JQUERY...

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

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

Ou tout simplement cible les personnages principaux à vous inquiéter au sujet de & , 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>
1
répondu Dave Brown 2016-02-08 14:14:43

pur exemple D'échappement JavaScript:

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;"
1
répondu Andrew Luca 2017-10-29 08:23:38
function htmlDecode(t){
   if (t) return $('<div />').html(t).text();
}

fonctionne comme un charme

0
répondu d-_-b 2013-06-03 02:48:33

Cette réponse fournit le jQuery et normal JS méthodes, mais c'est plus court, sans l'utilisation de 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 ennuient, 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 fonction escape() était dépréciée dans la version JavaScript 1.5 . encodeURI() ou encodeURIComponent() sont des solutions de rechange, mais ils l'ignorent ' , de sorte que la dernière ligne de code serait à son tour tenu de ce:

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

tous les principaux navigateurs prennent encore en charge le code court, et compte tenu du nombre d'anciens sites web, Je doute que cela va changer bientôt.

0
répondu Cees Timmerman 2017-05-23 12:02:46

si vous enregistrez ces informations dans une base de données , son erreur pour échapper HTML en utilisant un côté client script, cela doit être fait dans le serveur . Sinon, il est facile de contourner votre protection XSS.

pour clarifier mon point, voici un exemple en utilisant l'une des réponses:

disons que vous utilisez la fonction escapeHtml pour échapper au Html de un commentaire dans votre blog et ensuite le poster 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:

  • Modifier les paramètres de la requête POST et remplacer le Commentaire par le code javascript.
  • remplace la fonction escapeHtml à l'aide de la console du navigateur.

si l'utilisateur collait cet extrait dans la console, il contournerait la validation XSS:

function escapeHtml(string){
   return string
}
-2
répondu Kauê Gimenes 2015-03-13 18:20:05

toutes les solutions sont inutiles si vous n'empêchez pas la ré-évasion, par exemple la plupart des solutions continueraient à é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] + ";";
        }
    ) : "";
};
-2
répondu C Nimmanant 2016-02-08 14:15:24