Question

Est-ce que quelqu'un connaît un moyen simple d'échapper au HTML des chaînes jQuery?Je dois pouvoir transmettre une chaîne arbitraire et la faire échapper correctement 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 pour y parvenir.

Était-ce utile?

La solution

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;

Autres conseils

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

Si vous recherchez du HTML, il n'y en a que trois qui, à mon avis, seraient vraiment nécessaires :

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

En fonction de votre cas d'utilisation, vous devrez peut-être également effectuer des opérations telles que " à &quot;.Si la liste devenait 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() ne l'échappera que pour les URL, pas pour le HTML.

J'ai écrit une toute petite fonction qui fait cela.Il ne fait qu'échapper ", &, < et > (mais c'est généralement tout ce dont vous avez besoin de toute façon).Elle est légèrement plus élégante que les solutions proposées précédemment dans la mesure où elle utilise uniquement un .replace() pour faire toute la conversion.(MODIFIER 2 : Complexité du code réduite rendant la fonction encore plus petite et plus soignée, si vous êtes curieux de connaître le code original, voir la fin de cette réponse.)

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

Il s'agit de Javascript simple, aucun jQuery n'est utilisé.

S'échapper / et ' aussi

Modifier en réponse à élémentle commentaire de.

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 tous les deux dans la classe de caractères de l'expression régulière (c'est-à-direà l'intérieur de /[...]/g) et comme entrée dans le chr objet.(MODIFIER 2 : Cette fonction a également été raccourcie, 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 l'apostrophe (l'entité symbolique &apos; aurait pu être utilisé à la place – il est défini en XML, mais n'était pas initialement inclus dans la spécification HTML et pourrait donc ne pas être pris en charge par tous les navigateurs.Voir: Article Wikipédia 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'entités hexadécimales, mais je n'arrive pas à trouver la source de cela pour le moment.(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 signification particulière en HTML et n'ont pas d'importance. besoin être évadé.

Original escapeHtml Fonction

MODIFIER 2 : La fonction d'origine utilisait une variable (chr) pour stocker l'objet nécessaire au .replace() rappeler.Cette variable avait également besoin d'une fonction anonyme supplémentaire pour la définir, 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 est la plus rapide.Si c’est le cas, n’hésitez pas à ajouter des informations et des liens à ce sujet ici.

Assez simple à utiliser le soulignement :

_.escape(string) 

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

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;

Modifier:Cela n’échappe pas aux guillemets.Le seul cas où les guillemets doivent ê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.

Modifier 2 :Si les performances sont cruciales, la solution la plus performante (d'environ 50 %) reste une série de remplacements d'expressions régulières.Les navigateurs modernes détecteront que les expressions régulières ne contiennent aucun opérateur, juste une chaîne, et les réduiront toutes en une seule opération.

Voici une fonction JavaScript propre et claire.Il échappera le texte tel que « quelques < plusieurs » en « quelques <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;');
}

Après les derniers tests, je peux recommander le plus rapide et complètement navigateur croisé compatible javascript natif Solution (DOM) :

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 performance finale comparaison (question de pile).

Essayer Underscore.string lib, cela fonctionne avec jQuery.

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

sortir:

'&lt;div&gt;Blah blah blah&lt;/div&gt;'

J'ai amélioré l'exemple moustache.js en ajoutant le 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, c'est assez simple à utiliser "Some <text>, more Text&Text".escapeHTML()

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

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

var escapedHtml = html.replace(/&/g, '&amp;')
                      .replace(/>/g, '&gt;')
                      .replace(/</g, '&lt;')
                      .replace(/"/g, '&quot;')
                      .replace(/'/g, '&apos;');

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

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

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

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

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

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

Tu peux encoder tous les caractères dans votre chaîne comme ceci :

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

Ou juste cibler les personnages principaux se préoccuper 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>

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;"
function htmlDecode(t){
   if (t) return $('<div />').html(t).text();
}

fonctionne à merveille

Cette réponse fournit les méthodes jQuery et JS normales, mais celle-ci 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, le escape() la fonction était obsolète dans la version JavaScript 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 étant donné le nombre d'anciens sites Web, je doute que cela change bientôt.

Si vous enregistrez ces informations dans un base de données, ce n'est pas bien d'échapper au 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 propos, voici un exemple utilisant l'une des réponses :

Disons que vous utilisez la fonction escapeHtml pour échapper au code HTML d'un commentaire sur 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, cela contournera la validation XSS :

function escapeHtml(string){
   return string
}

Toutes les solutions sont inutiles si vous n'empêchez pas la réévasion, par ex.la plupart des solutions continueraient à s'é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] + ";";
        }
    ) : "";
};
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top