Puis-je échapper les caractères spéciaux html en javascript?

201

Je souhaite afficher un texte en HTML par une fonction javascript. Comment puis-je échapper les caractères spéciaux html dans JS? Existe-t-il une API?

fernando123
la source
11
Ce n'est pas un doublon, car cette question ne concerne pas jQuery. Je ne m'intéresse qu'à celui-ci, puisque je n'utilise pas jQuery ...
lvella
4
doublon possible de l' équivalent HtmlSpecialChars en Javascript?
Bergi

Réponses:

330
function escapeHtml(unsafe) {
    return unsafe
         .replace(/&/g, "&")
         .replace(/</g, "&lt;")
         .replace(/>/g, "&gt;")
         .replace(/"/g, "&quot;")
         .replace(/'/g, "&#039;");
 }
bjornd
la source
11
Pourquoi "& # 039;" et non "& apos;" ?
sereda
2
Je pense que les expressions régulières dans les replace()appels ne sont pas nécessaires. De vieilles chaînes simples à caractère unique feraient aussi bien l'affaire.
jamix
22
@jamix Vous ne pouvez pas faire un remplacement global avec des chaînes brutes, tandis que les moteurs de navigateur modernes optimisent assez bien l'expression régulière simple.
bjornd
5
existe-t-il une API standard ou c'est le seul moyen?
Sunil Garg
55

function escapeHtml(html){
  var text = document.createTextNode(html);
  var p = document.createElement('p');
  p.appendChild(text);
  return p.innerHTML;
}

// Escape while typing & print result
document.querySelector('input').addEventListener('input', e => {
  console.clear();
  console.log( escapeHtml(e.target.value) );
});
<input style='width:90%; padding:6px;' placeholder='&lt;b&gt;cool&lt;/b&gt;'>

spiderlama
la source
Travailler ici mais ne fonctionne pas pour moi hors ligne dans le navigateur
48

Vous pouvez utiliser la .text()fonction de jQuery .

Par exemple:

http://jsfiddle.net/9H6Ch/

De la documentation jQuery concernant la .text()fonction:

Nous devons être conscients que cette méthode échappe à la chaîne fournie si nécessaire pour qu'elle s'affiche correctement en HTML. Pour ce faire, il appelle la méthode DOM .createTextNode (), n'interprète pas la chaîne comme HTML.

Les versions précédentes de la documentation jQuery le formulaient de cette façon (nous soulignons ):

Nous devons être conscients que cette méthode échappe à la chaîne fournie si nécessaire pour qu'elle s'affiche correctement en HTML. Pour ce faire, il appelle la méthode DOM .createTextNode (), qui remplace les caractères spéciaux par leurs équivalents d'entité HTML (tels que & lt; for <).

jeremysawesome
la source
3
Vous pouvez même l'utiliser sur un élément frais si vous voulez simplement convertir comme ceci: const str = "foo<>'\"&"; $('<div>').text(str).html()rendementsfoo&lt;&gt;'"&amp;
amoebe
28

Je pense que j'ai trouvé la bonne façon de le faire ...

// Create a DOM Text node:
var text_node = document.createTextNode(unescaped_text);

// Get the HTML element where you want to insert the text into:
var elem = document.getElementById('msg_span');

// Optional: clear its old contents
//elem.innerHTML = '';

// Append the text node into it:
elem.appendChild(text_node);
lvella
la source
J'ai appris quelque chose de nouveau sur HTML aujourd'hui. w3schools.com/jsref/met_document_createtextnode.asp .
Sellorio
1
Sachez que le contenu du nœud de texte n'est pas échappé si vous essayez d'y accéder comme ceci:document.createTextNode("<script>alert('Attack!')</script>").textContent
maechler
C'est la bonne façon si vous ne faites que définir du texte. C'est aussi textContent mais apparemment ce n'est pas bien supporté. Cela ne fonctionnera pas cependant si vous créez une chaîne avec du texte de certaines parties en HTML, alors vous devez toujours vous échapper.
jgmjgm
21

C'est, de loin, le moyen le plus rapide que je connaisse. De plus, il fait tout sans ajouter, supprimer ou modifier des éléments sur la page.

function escapeHTML(unsafeText) {
    let div = document.createElement('div');
    div.innerText = unsafeText;
    return div.innerHTML;
}
arjunpat
la source
7
Avertissement: il n'échappe pas aux guillemets, vous ne pouvez donc pas utiliser la sortie à l'intérieur des valeurs d'attribut dans le code HTML. Par exemple, vous var divCode = '<div data-title="' + escapeHTML('Jerry "Bull" Winston') + '">Div content</div>'obtiendrez un code HTML non valide!
izogfif
17

Il était intéressant de trouver une meilleure solution:

var escapeHTML = function(unsafe) {
  return unsafe.replace(/[&<"']/g, function(m) {
    switch (m) {
      case '&':
        return '&amp;';
      case '<':
        return '&lt;';
      case '"':
        return '&quot;';
      default:
        return '&#039;';
    }
  });
};

Je n'analyse pas >car il ne casse pas le code XML / HTML dans le résultat.

Voici les repères: http://jsperf.com/regexpairs Aussi, j'ai créé une escapefonction universelle : http://jsperf.com/regexpairs2

iegik
la source
1
Il est intéressant de voir que l'utilisation du commutateur est beaucoup plus rapide que la carte. Je ne m'attendais pas à ça! Merci d'avoir partagé!
Peter T.16
Il y a beaucoup plus de caractères Unicode que vous ne pourriez en coder et prendre en compte. Je ne recommanderais pas du tout cette méthode manuelle.
vsync
Pourquoi voudriez-vous échapper à des caractères multi-octets? Utilisez simplement UTF-8 partout.
Neonit
4
Sauter> peut potentiellement casser le code. Vous devez garder à l'esprit que l'intérieur de <> est également html. Dans ce cas, sauter> se cassera. Si vous ne vous échappez qu'entre les balises, vous n'aurez probablement besoin que des touches d'échappement <et &.
jgmjgm
8

La façon la plus concise et la plus performante d'afficher du texte non codé est d'utiliser la textContentpropriété.

Plus rapide que l'utilisation innerHTML. Et c'est sans prendre en compte l'échappée des frais généraux.

document.body.textContent = 'a <b> c </b>';

utilisateur
la source
@ZzZombo, il est tout à fait normal que cela ne fonctionne pas avec les balises de style et de script. Lorsque vous leur ajoutez du contenu, vous ajoutez du code , pas du texte , utilisez innerHTML dans ce cas. De plus, vous n'avez pas besoin d'y échapper, ce sont deux balises spéciales qui ne sont pas analysées en HTML. Lors de l'analyse, leur contenu est traité comme du texte jusqu'à ce que la séquence de fermeture </soit respectée.
utilisateur
6

Les éléments DOM prennent en charge la conversion de texte en HTML en l'attribuant à innerText . innerText n'est pas une fonction mais son affectation fonctionne comme si le texte était échappé.

document.querySelectorAll('#id')[0].innerText = 'unsafe " String >><>';
teknopaul
la source
1
Au moins dans Chrome, l'attribution de texte multiligne ajoute des <br>éléments à la place des sauts de ligne, qui peuvent casser certains éléments, comme les styles ou les scripts. Le createTextNoden'est pas sujet à ce problème.
ZzZombo
1
innerTexta quelques problèmes hérités / spec. Mieux à utiliser textContent.
Roy Tinker
3

Vous pouvez encoder chaque caractère de votre chaîne:

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

Ou ciblez simplement les personnages principaux dont vous devez vous soucier (&, inebreaks, <,>, "et ') comme:

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

test.value=encode('How to encode\nonly html tags &<>\'" nice & fast!');

/*************
* \x26 is &ampersand (it has to be first),
* \x0A is newline,
*************/
<textarea id=test rows="9" cols="55">&#119;&#119;&#119;&#46;&#87;&#72;&#65;&#75;&#46;&#99;&#111;&#109;</textarea>

Dave Brown
la source
Écrire votre propre fonction d'échappement est généralement une mauvaise idée. D'autres réponses sont meilleures à cet égard.
jannis
2

Une doublure (pour ES6 +):

var escapeHtml = s => (s + '').replace(/[&<>"']/g, m => ({
    '&': '&amp;', '<': '&lt;', '>': '&gt;',
    '"': '&quot;', "'": '&#39;'
})[m]);

Pour les anciennes versions:

function escapeHtml(s) {
    return (s + '').replace(/[&<>"']/g, function (m) {
        return ({
            '&': '&amp;', '<': '&lt;', '>': '&gt;',
            '"': '&quot;', "'": '&#39;'
        })[m];
    });
}
Ossia
la source
0

Nous avons rencontré ce problème lors de la création d'une structure DOM. Cette question m'a aidé à le résoudre. Je voulais utiliser un double chevron comme séparateur de chemin, mais l'ajout d'un nouveau nœud de texte entraînait directement l'affichage du code de caractère d'échappement, plutôt que le caractère lui-même:

var _div = document.createElement('div');
var _separator = document.createTextNode('&raquo;');
//_div.appendChild(_separator); /* this resulted in '&raquo;' being displayed */
_div.innerHTML = _separator.textContent; /* this was key */
Silas
la source
0

Si vous utilisez déjà des modules dans votre application, vous pouvez utiliser le module escape-html .

import escapeHtml from 'escape-html';
const unsafeString = '<script>alert("XSS");</script>';
const safeString = escapeHtml(unsafeString);
Shimon S
la source
-3

Essayez ceci en utilisant la prototype.jsbibliothèque:

string.escapeHTML();

Essayez une démo

Chanceux
la source
5
Cela nécessite la bibliothèque "prototype.js", qui n'était pas immédiatement apparente dans la démo. :(
audiodude
-4

J'ai trouvé cette solution.

Supposons que nous voulons ajouter du code HTML à l'élément avec des données dangereuses de l'utilisateur ou de la base de données.

var unsafe = 'some unsafe data like <script>alert("oops");</script> here';

var html = '';
html += '<div>';
html += '<p>' + unsafe + '</p>';
html += '</div>';

element.html(html);

Ce n'est pas sûr contre les attaques XSS. Maintenant, ajoutez ceci.

$(document.createElement('div')).html(unsafe).text();

Donc c'est

var unsafe = 'some unsafe data like <script>alert("oops");</script> here';

var html = '';
html += '<div>';
html += '<p>' + $(document.createElement('div')).html(unsafe).text(); + '</p>';
html += '</div>';

element.html(html);

Pour moi, c'est beaucoup plus facile que d'utiliser .replace()et cela supprimera !!! toutes les balises html possibles (j'espère).

Kostiantyn
la source
C'est une idée dangereuse, elle analyse la chaîne HTML non sécurisée en HTML, si l'élément était attaché au DOM, il serait exeute. utilisez plutôt .innerText.
teknopaul
Ce n'est pas sûr. Il se transforme &lt;script&gt;en <script>.
fgb