Czy mogę uciec od znaków specjalnych HTML w javascript?


Odpowiedzi:


330
function escapeHtml(unsafe) {
    return unsafe
         .replace(/&/g, "&")
         .replace(/</g, "&lt;")
         .replace(/>/g, "&gt;")
         .replace(/"/g, "&quot;")
         .replace(/'/g, "&#039;");
 }

11
Dlaczego „& # 039;” a nie „& apos;” ?
sereda


2
Myślę, że wyrażenia regularne w replace()połączeniach są niepotrzebne. Równie dobrze sprawdzą się zwykłe stare ciągi jednoznakowe.
jamix

22
@jamix Nie można dokonać globalnego zastąpienia nieprzetworzonymi ciągami, podczas gdy nowoczesne silniki przeglądarek całkiem dobrze optymalizują proste wyrażenia regularne.
bjornd

5
czy jest jakiś standardowy interfejs API czy to jedyny sposób?
Sunil Garg

56

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


Działa tutaj, ale nie działa dla mnie offline w przeglądarce

47

Możesz użyć .text()funkcji jQuery .

Na przykład:

http://jsfiddle.net/9H6Ch/

Z dokumentacji jQuery dotyczącej .text()funkcji:

Musimy zdawać sobie sprawę, że ta metoda ucieka przed podanym ciągiem znaków, aby był poprawnie renderowany w HTML. W tym celu wywołuje metodę DOM .createTextNode (), nie interpretuje ciągu jako HTML.

Poprzednie wersje Dokumentacji jQuery sformułowały to w ten sposób ( wyróżnienie dodane ):

Musimy zdawać sobie sprawę, że ta metoda ucieka przed podanym ciągiem znaków, aby był poprawnie renderowany w HTML. W tym celu wywołuje metodę DOM .createTextNode (), która zastępuje znaki specjalne ich odpowiednikami encji HTML (np. & Lt; for <).


3
Możesz nawet użyć go na świeżym elemencie, jeśli chcesz po prostu przekonwertować w ten sposób: const str = "foo<>'\"&"; $('<div>').text(str).html()wydajnościfoo&lt;&gt;'"&amp;
amoebe

28

Myślę, że znalazłem właściwy sposób, aby to zrobić ...

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

Nauczyłem się dziś czegoś nowego o HTML. w3schools.com/jsref/met_document_createtextnode.asp .
Sellorio

1
Należy pamiętać, że treść węzła tekstowego nie jest document.createTextNode("<script>alert('Attack!')</script>").textContent
usuwana,

Jest to poprawny sposób, jeśli wszystko, co robisz, to ustawianie tekstu. To także textContent, ale najwyraźniej nie jest dobrze obsługiwane. Nie zadziała to jednak, jeśli budujesz ciąg znaków z tekstem częściowym HTML-em, to nadal musisz uciec.
jgmjgm


21

To zdecydowanie najszybszy sposób, w jaki to widziałem. Ponadto robi to wszystko bez dodawania, usuwania lub zmieniania elementów na stronie.

function escapeHTML(unsafeText) {
    let div = document.createElement('div');
    div.innerText = unsafeText;
    return div.innerHTML;
}

7
Ostrzeżenie: nie zawiera cudzysłowów, więc nie można użyć wyjściowych wartości atrybutów w kodzie HTML. Np. var divCode = '<div data-title="' + escapeHTML('Jerry "Bull" Winston') + '">Div content</div>'Da niepoprawny HTML!
izogfif

17

Ciekawe było znalezienie lepszego rozwiązania:

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

Nie analizuję, >ponieważ nie psuje kodu XML / HTML w wyniku.

Oto testy: http://jsperf.com/regexpairs Ponadto stworzyłem funkcję uniwersalną escape: http://jsperf.com/regexpairs2


1
Interesujące jest to, że użycie przełącznika jest znacznie szybsze niż mapa. Nie spodziewałem się tego! Dzięki za udostępnienie!
Peter T.

Istnieje o wiele więcej znaków Unicode, niż można to zrobić, biorąc pod uwagę kod. W ogóle nie poleciłbym tej metody ręcznej.
vsync

Dlaczego w ogóle unikasz znaków wielobajtowych? Po prostu użyj UTF-8 wszędzie.
Neonit,

4
Pomijanie> może potencjalnie uszkodzić kod. Należy pamiętać, że wewnątrz <> znajduje się również HTML. W takim przypadku pomijanie> się zepsuje. Jeśli uciekasz tylko między tagami, prawdopodobnie potrzebujesz tylko klawiszy Escape <i &.
jgmjgm

8

Najbardziej zwięzłym i wydajnym sposobem wyświetlania niekodowanego tekstu jest użycie textContentwłaściwości.

Szybszy niż używanie innerHTML. I to bez uwzględnienia ucieczki.

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


@ZzZombo, całkowicie normalne jest to, że nie działa ze znacznikami stylu i skryptów. Kiedy dodajesz do nich treść, dodajesz kod , a nie tekst , w tym przypadku użyj innerHTML. Co więcej, nie musisz go uciekać, są to dwa specjalne tagi, które nie są analizowane jako HTML. Podczas analizowania ich zawartość jest traktowana jako tekst do momentu </spełnienia sekwencji zamykającej .
użytkownik

6

Elementy DOM obsługują konwersję tekstu na HTML poprzez przypisanie do innerText . innerText nie jest funkcją, ale przypisywanie do niej działa tak, jakby tekst został poprzedzony znakiem ucieczki.

document.querySelectorAll('#id')[0].innerText = 'unsafe " String >><>';

1
Przynajmniej w Chrome przypisywanie tekstu wielowierszowego dodaje <br>elementy zamiast znaków nowej linii, które mogą rozkładać niektóre elementy, takie jak style lub skrypty. Nie createTextNodejest podatny na ten problem.
ZzZombo,

1
innerTextma pewne problemy ze starszymi wersjami / specyfikacjami. Lepszy w użyciu textContent.
Roy Tinker,

3

Możesz zakodować każdy znak w ciągu:

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

Lub po prostu celuj w głównych bohaterów, aby się martwić (&, inebreaks, <,>, "i '), takich jak:

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>


Pisanie własnej funkcji ucieczki jest ogólnie złym pomysłem. Inne odpowiedzi są lepsze pod tym względem.
jannis

2

Jednowarstwowy (dla ES6 +):

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

W przypadku starszych wersji:

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

0

Ten problem pojawił się podczas tworzenia struktury DOM. To pytanie pomogło mi rozwiązać. Chciałem użyć podwójnego szewronu jako separatora ścieżki, ale dodanie nowego węzła tekstowego bezpośrednio spowodowało wyświetlenie kodu znaku ucieczki zamiast samego znaku:

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 */

0

Jeśli korzystasz już z modułów w swojej aplikacji, możesz użyć modułu Escape-HTML .

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


-4

Wymyśliłem to rozwiązanie.

Załóżmy, że chcemy dodać do elementu trochę html z niebezpiecznymi danymi od użytkownika lub bazy danych.

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

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

element.html(html);

Jest niebezpieczny przed atakami XSS. Teraz dodaj to.

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

Tak jest

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

Dla mnie jest to o wiele łatwiejsze niż używanie .replace()i usunie !!! wszystkie możliwe tagi HTML (mam nadzieję).


to niebezpieczny pomysł, analizuje niebezpieczny ciąg HTML jako HTML, gdyby element został dołączony do DOM, to by go wyegzekwował. zamiast tego użyj .innerText.
teknopaul

To nie jest bezpieczne. Przekształca się &lt;script&gt;w <script>.
fgb
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.