Kann ich HTML-Sonderzeichen in Javascript entkommen?

199

Ich möchte einen Text in HTML durch eine Javascript-Funktion anzeigen. Wie kann ich HTML-Sonderzeichen in JS umgehen? Gibt es eine API?

fernando123
quelle
11
Dies ist kein Duplikat, da diese Frage nicht nach jQuery fragt. Ich interessiere mich nur für dieses, da ich jQuery nicht benutze ...
lvella
4
Mögliches Duplikat des HtmlSpecialChars-Äquivalents in Javascript?
Bergi

Antworten:

329
function escapeHtml(unsafe) {
    return unsafe
         .replace(/&/g, "&")
         .replace(/</g, "&lt;")
         .replace(/>/g, "&gt;")
         .replace(/"/g, "&quot;")
         .replace(/'/g, "&#039;");
 }
bjornd
quelle
11
Warum "& # 039;" und nicht "& apos;" ?
Sereda
2
Ich denke, reguläre Ausdrücke in replace()Anrufen sind unnötig. Einfache alte Einzelzeichenfolgen würden genauso gut funktionieren.
Jamix
21
@jamix Sie können keinen globalen Ersatz durch rohe Zeichenfolgen vornehmen, während moderne Browser-Engines den einfachen regulären Ausdruck ziemlich gut optimieren.
bjornd
4
Gibt es eine Standard-API oder ist dies der einzige Weg?
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
quelle
Hier arbeiten, aber nicht offline für mich im Browser arbeiten
49

Sie können die .text()Funktion von jQuery verwenden .

Beispielsweise:

http://jsfiddle.net/9H6Ch/

Aus der jQuery-Dokumentation zur .text()Funktion:

Wir müssen uns bewusst sein, dass diese Methode bei Bedarf der angegebenen Zeichenfolge entgeht, damit sie korrekt in HTML gerendert wird. Dazu ruft es die DOM-Methode .createTextNode () auf und interpretiert die Zeichenfolge nicht als HTML.

In früheren Versionen der jQuery-Dokumentation wurde dies folgendermaßen formuliert ( Hervorhebung hinzugefügt ):

Wir müssen uns bewusst sein, dass diese Methode bei Bedarf der angegebenen Zeichenfolge entgeht, damit sie korrekt in HTML gerendert wird. Zu diesem Zweck wird die DOM-Methode .createTextNode () aufgerufen, die Sonderzeichen durch ihre HTML-Entitätsäquivalente ersetzt (z. B. & lt; für <).

jeremysawesome
quelle
3
Sie können es sogar für ein const str = "foo<>'\"&"; $('<div>').text(str).html()foo&lt;&gt;'"&amp;
neues
28

Ich glaube, ich habe den richtigen Weg gefunden ...

// 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
quelle
Ich habe heute etwas Neues über HTML gelernt. w3schools.com/jsref/met_document_createtextnode.asp .
Sellorio
1
document.createTextNode("<script>alert('Attack!')</script>").textContent
Beachten
Dies ist der richtige Weg, wenn Sie nur Text einstellen. Das ist auch textContent, aber anscheinend wird es nicht gut unterstützt. Dies funktioniert jedoch nicht, wenn Sie eine Zeichenfolge mit einigen Teilen Text und HTML erstellen, müssen Sie trotzdem entkommen.
jgmjgm
20

Dies ist bei weitem der schnellste Weg, den ich je gesehen habe. Außerdem wird alles erledigt, ohne Elemente auf der Seite hinzuzufügen, zu entfernen oder zu ändern.

function escapeHTML(unsafeText) {
    let div = document.createElement('div');
    div.innerText = unsafeText;
    return div.innerHTML;
}
Arjunpat
quelle
7
Warnung: Es werden keine Anführungszeichen ausgegeben, sodass Sie die Ausgabe nicht in Attributwerten im HTML-Code verwenden können. ZB var divCode = '<div data-title="' + escapeHTML('Jerry "Bull" Winston') + '">Div content</div>'ergibt ungültiges HTML!
izogfif
16

Es war interessant, eine bessere Lösung zu finden:

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

Ich analysiere nicht, >weil es XML / HTML-Code im Ergebnis nicht bricht.

Hier sind die Benchmarks: http://jsperf.com/regexpairs Außerdem habe ich eine universelle escapeFunktion erstellt: http://jsperf.com/regexpairs2

iegik
quelle
1
Es ist interessant zu sehen, dass die Verwendung des Schalters erheblich schneller ist als die Karte. Das habe ich nicht erwartet! Danke für das Teilen!
Peter T.
Es gibt viel, viel mehr Unicode-Zeichen, als Sie codieren und berücksichtigen könnten. Ich würde diese manuelle Methode überhaupt nicht empfehlen.
vsync
Warum würden Sie Multibyte-Zeichen überhaupt entkommen? Verwenden Sie UTF-8 einfach überall.
Neonit
3
Überspringen> kann möglicherweise den Code beschädigen. Sie müssen bedenken, dass im <> auch HTML enthalten ist. In diesem Fall wird das Überspringen> unterbrochen. Wenn Sie nur zwischen Tags fliehen, benötigen Sie wahrscheinlich nur Escape <und &.
jgmjgm
8

Die prägnanteste und performanteste Möglichkeit, nicht codierten Text anzuzeigen, ist die Verwendung von textContentEigenschaften.

Schneller als mit innerHTML. Und das ohne Berücksichtigung des Overheads.

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

Benutzer
quelle
@ZzZombo, es ist völlig normal, dass es nicht mit Stil- und Skript-Tags funktioniert. Wenn Sie ihnen Inhalte hinzufügen, fügen Sie Code hinzu , nicht Text . Verwenden Sie in diesem Fall innerHTML. Darüber hinaus müssen Sie nicht entkommen, dies sind zwei spezielle Tags, die nicht als HTML analysiert werden. Beim Parsen wird ihr Inhalt als Text behandelt, bis die Abschlusssequenz erreicht </ist.
Benutzer
6

DOM-Elemente unterstützen die Konvertierung von Text in HTML durch Zuweisung zu innerText . innerText ist keine Funktion, aber die Zuweisung funktioniert so, als ob der Text maskiert wäre.

document.querySelectorAll('#id')[0].innerText = 'unsafe " String >><>';
Teknopaul
quelle
1
Zumindest in Chrome werden durch das Zuweisen von mehrzeiligem Text <br>Elemente anstelle von Zeilenumbrüchen hinzugefügt, die bestimmte Elemente wie Stile oder Skripte beschädigen können. Das createTextNodeist nicht anfällig für dieses Problem.
ZzZombo
1
innerTexthat einige Legacy- / Spezifikationsprobleme. Besser zu benutzen textContent.
Roy Tinker
3

Sie können jedes Zeichen in Ihrer Zeichenfolge codieren:

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

Oder zielen Sie einfach auf die Hauptfiguren, über die Sie sich Sorgen machen möchten (&, Inebreaks, <,>, "und '), wie:

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
quelle
Das Schreiben einer eigenen Escape-Funktion ist im Allgemeinen eine schlechte Idee. Andere Antworten sind in dieser Hinsicht besser.
Jannis
2

Ein Einzeiler (für ES6 +):

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

Für ältere Versionen:

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

Ist beim Erstellen einer DOM-Struktur auf dieses Problem gestoßen. Diese Frage hat mir geholfen, sie zu lösen. Ich wollte einen Doppel-Chevron als Pfadtrennzeichen verwenden, aber das Anhängen eines neuen Textknotens führte direkt dazu, dass der maskierte Zeichencode angezeigt wurde und nicht das Zeichen selbst:

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
quelle
0

Wenn Sie bereits Module in Ihrer App verwenden, können Sie das Escape-HTML- Modul verwenden.

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

Versuchen Sie dies mithilfe der prototype.jsBibliothek:

string.escapeHTML();

Probieren Sie eine Demo aus

Glücklich
quelle
5
Dies erfordert die Bibliothek "prototype.js", die in der Demo nicht sofort ersichtlich war. :(
Audiodude
-4

Ich habe diese Lösung gefunden.

Nehmen wir an, wir möchten dem Element HTML mit unsicheren Daten des Benutzers oder der Datenbank hinzufügen.

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

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

element.html(html);

Es ist unsicher gegen XSS-Angriffe. Fügen Sie dies nun hinzu.

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

So ist es

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

Für mich ist das viel einfacher als zu benutzen .replace()und es wird entfernt !!! alle möglichen HTML-Tags (hoffe ich).

Kostiantyn
quelle
Dies ist eine gefährliche Idee. Sie analysiert den unsicheren HTML-String als HTML. Wenn das Element an das DOM angehängt würde, würde es ausgeführt. Verwenden Sie stattdessen .innerText.
Teknopaul
Das ist nicht sicher. Es wandelt sich &lt;script&gt;in <script>.
FGB