Unikanie ciągów HTML za pomocą jQuery

609

Czy ktoś zna prosty sposób na ucieczkę HTML z ciągów znaków w jQuery ? Muszę być w stanie przekazać dowolny ciąg znaków i odpowiednio wstawić znak ucieczki w celu wyświetlenia na stronie HTML (zapobiegając atakom JavaScript / HTML). Jestem pewien, że można rozszerzyć jQuery, aby to zrobić, ale w tej chwili nie wiem wystarczająco dużo o frameworku, aby to osiągnąć.

Strona
źródło
Zobacz także perf: jsperf.com/…
Christophe Roussy

Odpowiedzi:

445

Ponieważ używasz jQuery , możesz po prostu ustawić właściwość elementu text:

// 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;
Travis
źródło
57
Pominąłeś punkt, w którym musisz uzyskać dostęp do $ („div.someClass”). Html (), aby wydostać się z wersji.
Morten Christiansen
16
Nie jest to bezpieczne dla różnych przeglądarek, jeśli Twój ciąg ma białe spacje i \ n \ r \ t znaki w nim
nivcaner
20
@travis Jest to udokumentowane na stronie internetowej jQuery: „Ze względu na różnice w parserach HTML w różnych przeglądarkach zwracany tekst może różnić się znakami nowej linii i innymi spacjami”. api.jquery.com/text
geofflee
3
@mklement, jeśli już używasz tego rozwiązania, nie będziesz mieć żadnych problemów z robieniem czegoś takiego: $(element2).attr("some-attr", $(element1).html());Zobacz ten przykład: jsbin.com/atibig/1/edit
travis
16
To NIE unika cytatów i podwójnych cudzysłowów, co jest złe! wonko.com/post/html-escaping
Lior
600

Istnieje również rozwiązanie z mustache.js

var entityMap = {
  '&': '&amp;',
  '<': '&lt;',
  '>': '&gt;',
  '"': '&quot;',
  "'": '&#39;',
  '/': '&#x2F;',
  '`': '&#x60;',
  '=': '&#x3D;'
};

function escapeHtml (string) {
  return String(string).replace(/[&<>"'`=\/]/g, function (s) {
    return entityMap[s];
  });
}
Tom Gruner
źródło
7
Zauważ, że, co ciekawe, 'jest odwzorowany na byt o formacie dziesiętnym , podczas gdy /używa formatu szesnastkowego .
mklement0 18.04.13
43
To powinna być zaakceptowana odpowiedź - jest prosta, wydajna, nie wymaga żadnych zależności i robi dokładnie to, co jest zamierzone, bez niejasnych włamań.
lorefnon
6
co wytyczne dotyczące konwersji \ndo <br>?
amwinter
2
Oto zaktualizowany link do źródła: github.com/janl/mustache.js/blob/…
mjackson
8
@amwinter, rozszerzyłem skrypt powyżej dodając „\ n”: „<br>” do mapy encji i zaktualizowałem wyrażenie regularne do / [& <> "'\ /] | [\ n] / g
walv
182
$('<div/>').text('This is fun & stuff').html(); // "This is fun &amp; stuff"

Źródło: http://debuggable.com/posts/encode-html-entities-with-jquery:480f4dd6-13cc-4ce9-8071-4710cbdd56cb

Henrik N.
źródło
11
Jak wspomniano w powyższej odpowiedzi, to rozwiązanie nie gwarantuje zachowania białych znaków.
geofflee
47
Należy zauważyć, że nie ma to wpływu na pojedyncze lub podwójne cudzysłowy. jeśli planujesz wstawić wartość do atrybutu HTML, może to stanowić problem.
Kip
6
@Kip: @travis stwierdził, że attr()metoda jQuery (od co najmniej 1.8.3) wykonuje własne kodowanie, dzięki czemu niekodowane ciągi mogą być przekazywane bezpośrednio ; np .:$('<div/>').attr('test-attr', '\'Tis "fun" & stuff')[0].outerHTML
mklement0
1
@tarekahf To dziwne. Jakiej wersji jQuery używasz? Czy przykładowy kod działa, jeśli skopiujesz go i wkleisz dosłownie? Działa dobrze z najnowszym jQuery (3.1.0) tutaj: jsbin.com/fazimigayo/1/edit?html,js,console,output (i powinno działać również na wszystkich wcześniejszych wersjach)
Henrik N
1
@tarekahf $('<div/>')tworzy nowy divelement, który nie jest dołączony do DOM. Więc nie zmieni żadnych istniejących elementów. To trochę mylące, w jaki sposób jQuery używa tej samej $()funkcji zarówno do znajdowania elementów ( $('div')), jak i do ich tworzenia, a także dla kilku innych rzeczy oprócz… :)
Henrik N
61

Jeśli uciekasz w stronę HTML, są tylko trzy, o których myślę, że byłyby naprawdę konieczne:

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

W zależności od przypadku zastosowania, może być konieczne, aby robić rzeczy, jak "się &quot;. Jeśli lista jest wystarczająco duża, użyłbym tablicy:

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() uniknie go tylko w przypadku adresów URL, a nie HTML.

tghw
źródło
13
To wyrażenie regularne przyniesie dziwne wyniki, jeśli dany kod HTML ma już znaki ucieczki. Na przykład ucieczka przed „Tomem i Jerrym” spowoduje wyprodukowanie „Tomka i Jerry'ego”
Ryan
12
Proszę użyć, varaby zadeklarować itemlokalnie; tak czy inaczej, nie używaj for … inpętli w ogóle podczas zapętlania tablicy! forZamiast tego użyj zwykłej pętli. Och, i to encodeURIComponentnie jest escapeURIComponent.
Marcel Korpel
3
Jeśli pracujesz z atrybutami znaczników, będziesz musiał także unikać cudzysłowów i / lub podwójnych cudzysłowów. Dokumentacja PHP dla htmlspecialchars zawiera przydatną listę konwersji, które wykonuje. php.net/htmlspecialchars
geofflee
4
Tylko rodzajem przypomnienia dla nowych ludzi, nie używaj tego, jeśli masz zamiar mieć znaków spoza alfabetu angielskiego gdzieś na swojej stronie ... Oczywiście nie będzie to zrobić, ponieważ znaków z akcentami jak „e”: &eacute; Oto lista jednostek HTML, w celach informacyjnych: w3schools.com/tags/ref_entities.asp
1
11
@ Ryan: Chociaż warto zauważyć, że to rozwiązanie nie obsługuje poprawnie już zakodowanych ciągów, nie jest również warte niczego, co to samo dotyczy większości - być może wszystkich - rozwiązań na tej stronie.
mklement0
37

Łatwy w użyciu podkreślnik:

_.escape(string) 

Podkreślenie to biblioteka narzędziowa, która zapewnia wiele funkcji, których nie zapewnia natywny js. Istnieje również lodash, który jest tym samym interfejsem API co podkreślenie, ale został przepisany, aby był bardziej wydajny.

chovy
źródło
36

Napisałem małą funkcję, która to robi. To tylko ucieka ", &, <i >(ale zwykle to wszystko, czego potrzeba w każdym razie). Jest nieco bardziej elegancki niż wcześniej proponowane rozwiązania, ponieważ używa tylko jednego .replace() do przeprowadzenia całej konwersji. ( EDYCJA 2: Zmniejszona złożoność kodu sprawia, że ​​funkcja jest jeszcze mniejsza i bardziej uporządkowana, jeśli jesteś ciekawy oryginalnego kodu, zobacz koniec tej odpowiedzi).

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

To jest zwykły Javascript, bez użycia jQuery.

Ucieczki /i 'zbyt

Edytuj w odpowiedzi na komentarz mklement .

Powyższą funkcję można łatwo rozszerzyć o dowolny znak. Aby określić więcej znaków do ucieczki, wystarczy wstawić je zarówno do klasy znaków w wyrażeniu regularnym (tj. Wewnątrz /[...]/g), jak i jako wpis w chrobiekcie. ( EDYCJA 2: ten sam sposób również skróciłem tę funkcję.)

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

Zwróć uwagę na powyższe użycie &#39;apostrofu ( &apos;zamiast tego można było użyć bytu symbolicznego - jest on zdefiniowany w XML, ale pierwotnie nie był uwzględniony w specyfikacji HTML i dlatego może nie być obsługiwany przez wszystkie przeglądarki. Zobacz: Artykuł w Wikipedii na temat kodowania znaków HTML ). Pamiętam też, że czytałem gdzieś, że używanie elementów dziesiętnych jest szerzej obsługiwane niż szesnastkowe, ale nie mogę teraz znaleźć źródła tego. (I nie może istnieć wiele przeglądarek, które nie obsługują bytów szesnastkowych.)

Uwaga: Dodawanie /i 'do listy znaków ucieczki nie jest aż tak przydatne, ponieważ nie mają one specjalnego znaczenia w HTML i nie wymagają ich zmieniać.

Oryginalny escapeHtml funkcja

EDYCJA 2: Oryginalna funkcja używała zmiennej ( chr) do przechowywania obiektu potrzebnego do .replace()wywołania zwrotnego. Ta zmienna wymagała także dodatkowej anonimowej funkcji do jej objęcia zasięgiem, dzięki czemu funkcja (niepotrzebnie) jest nieco większa i bardziej złożona.

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

Nie testowałem, która z dwóch wersji jest szybsza. Jeśli tak, możesz dodać tutaj informacje i linki na ten temat.

zrajm
źródło
Dziękujemy za poświęcenie czasu, @Zrajm. Dobra uwaga, że ​​nie trzeba uciekać; jakiś pomysł, dlaczego oba mustache.jsi underscore.jsto zrobić? A propos tego ostatniego: to tylko rozpoznaje podmioty numerycznych (reprezentującymi 'i /„), w wielkiej sześciokątną formę kiedy un ucieczki. W ten sposób tekst uciekł mustache.js- co ciekawie wykorzystuje mieszankę heksów. i formaty dziesiętne - nie będą poprawnie usuwane underscore.js. Zastanawiam się, jak radzą sobie z tym inne popularne biblioteki.
mklement0 18.04.13
1
Im niższa forma przypadek hex jest formą najbardziej obsługiwane, tak to jest (prawdopodobnie) formę, że biblioteki powinny przekształcić się . (Oczywiście obie formy powinny działać podczas konwersji z .) - Apostrofy 'mają jakąś zastrzeżoną funkcję w XML (a więc XHTML, jak sądzę?), Dlatego XML (ale nie HTML) ma nazwaną jednostkę &apos;. Nie wiem dokładnie, dlaczego lub w jaki sposób jest „zarezerwowany”. - Ukośniki są wyjątkowe w adresach URL, ale tak naprawdę nie gwarantują one włączenia ich do znaków ucieczki HTML (ponieważ kodowanie adresów URL jest czymś zupełnie innym).
zrajm
Re &apos;: poprawne: bezpieczne stosowanie tylko w XHTML ; prosto z ust źródła źródła - podkreśl moje: „(...) czytane przez zgodny procesor HTML , (...) użycie 'lub odwołania do encji niestandardowych mogą nie być obsługiwane (...)” - w praktyce : nowoczesne przeglądarki obsługują to nawet w HTML . Ponownie w przypadku liczb szesnastkowych. (to samo źródło; moje podkreślenie): „X musi być małymi literami w dokumentach XML. […] Hhhh może mieszać wielkie i małe litery, chociaż zwykle jest to duży styl .” Pozostawia nas zastanawianie się, kto zdecydował się zakodować ukośniki; może naprawdę pomieszanie URI i kodowania HTML?
mklement0
2
Końcowe przemyślenia: wydaje się, że kodowanie /nie jest potrzebne, ale kodowanie 'nadal wydaje się przydatne do bezpiecznego postępowania w przypadku, gdy zakodowany ciąg jest używany jako wartość atrybutu zawarta w pojedynczych cudzysłowach .
mklement0
Oba są powolne. Najszybszym rozwiązaniem z dwucyfrowym marginesem jest seria zamienników, które zamiast funkcji przekazują ciągi.
Adam Leggett,
34

Zdaję sobie sprawę, jak późno jestem na tę imprezę, ale mam bardzo łatwe rozwiązanie, które nie wymaga jQuery.

escaped = new Option(unescaped).innerHTML;

Edycja: To nie unika cytatów. Jedynym przypadkiem, w którym cytaty musiałyby być poprzedzone znakiem ucieczki, jest to, czy treść zostanie wklejona w linii do atrybutu w ciągu HTML. Trudno mi wyobrazić sobie przypadek, w którym zrobienie tego byłoby dobrym projektem.

Edycja 3: Aby znaleźć najszybsze rozwiązanie, sprawdź powyższą odpowiedź od Sarama. Ten jest najkrótszy.

Adam Leggett
źródło
To nie zmienia cytatów - przynajmniej teraz w Firefox 52.
getsetbro
1
Unikanie cudzysłowów jest funkcjonalnie istotne tylko w atrybutach. Ponieważ uciekamy <i >ucieczka od cytatów również nie ma żadnej korzyści, chyba że celem wygenerowanej treści jest przejście do atrybutu.
Adam Leggett,
31

Oto czysta, przejrzysta funkcja JavaScript. Będzie uciec od tekstu takiego jak „kilka <wiele” do „kilku <wiele”.

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;');
}
intrepidis
źródło
28

Po ostatnich testach mogę polecić najszybsze iw pełni kompatybilne z przeglądarkami natywne rozwiązanie javaScript (DOM):

function HTMLescape(html){
    return document.createElement('div')
        .appendChild(document.createTextNode(html))
        .parentNode
        .innerHTML
}

Jeśli powtórzysz to wiele razy, możesz to zrobić z raz przygotowanymi zmiennymi:

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

Spójrz na moje końcowe porównanie wydajności ( pytanie stosu ).

Saram
źródło
2
Czy konieczne jest użycie dwóch węzłów? A może tylko jeden:var p = document.createElement('p'); p.textContent = html; return p.innerHTML;
Dan Dascalescu,
2
@DanDascalescu: Zgodnie MDN The textContentfunkcja jest wyłącznie Chrome 1+ Firefox 2 IE9, Opera 9.64 i Safari 3 (oba opisywane "ewentualnie wcześniej"). W ten sposób złamałoby to roszczenie OP „całkowicie kompatybilne z różnymi przeglądarkami”.
zb226
p.innerText = html; return p.innerHTML
Bekim Bacaj
24

Wypróbuj Underscore.string lib, działa z jQuery.

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

wynik:

'&lt;div&gt;Blah blah blah&lt;/div&gt;'
Nikita Koksharov
źródło
20
Główna biblioteka podkreślania ma teraz funkcję _.escape()narzędzia.
codeape
15

Poprawiłem przykład mustache.js dodając escapeHTML()metodę do obiektu string.

var __entityMap = {
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    '"': '&quot;',
    "'": '&#39;',
    "/": '&#x2F;'
};

String.prototype.escapeHTML = function() {
    return String(this).replace(/[&<>"'\/]/g, function (s) {
        return __entityMap[s];
    });
}

W ten sposób jest dość łatwy w użyciu "Some <text>, more Text&Text".escapeHTML()

Jeena
źródło
Przydatne, ale także przeniosłem się __entityMapdo zakresu lokalnego funkcji. I wszystko to if (typeof String.prototype.escapeHTML !== 'function'){...}
zawarłem
15

escape() i unescape() są przeznaczone do kodowania / dekodowania ciągów dla adresów URL, a nie HTML.

Właściwie używam następującego fragmentu kodu, aby wykonać sztuczkę, która nie wymaga żadnych ram:

var escapedHtml = html.replace(/&/g, '&amp;')
                      .replace(/>/g, '&gt;')
                      .replace(/</g, '&lt;')
                      .replace(/"/g, '&quot;')
                      .replace(/'/g, '&apos;');
NicolasBernier
źródło
Jeśli chcesz mieć "s, musisz dodać przynajmniej 'i `` do walki. Są one naprawdę potrzebne tylko dla danych znaczników w elementach HTML. W przypadku samych danych HTML (poza znacznikami) wymagane są tylko pierwsze 3.
Marius
10

Jeśli masz plik underscore.js, użyj _.escape(bardziej wydajny niż metoda jQuery opublikowana powyżej):

_.escape('Curly, Larry & Moe'); // returns: Curly, Larry &amp; Moe
ronnbot
źródło
5

Jeśli wybierasz się na regex, w powyższym przykładzie tghw wystąpił błąd.

<!-- 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]]);
}
Wayne
źródło
2
Wierzę, że powinno być dla (var item in findReplace) {escaped = escaped.replace (findReplace [item] [0], findReplace [item] [1]); }
Chris Stephens
5

To niezły bezpieczny przykład ...

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;
    }
}
amrp
źródło
4
Jakie rodzaje wyjątków tam eliminujesz?
Stefan Majewsky
3

Możesz to łatwo zrobić za pomocą waniliowej js.

Po prostu dodaj dokument do węzła tekstowego. Zostanie to usunięte przez przeglądarkę.

var escaped = document.createTextNode("<HTML TO/ESCAPE/>")
document.getElementById("[PARENT_NODE]").appendChild(escaped)
raam86
źródło
2
(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));
    };
})();

Bez zmiennych globalnych, trochę optymalizacji pamięci. Stosowanie:

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

wynikiem jest:

"some&lt;tag&gt;and&amp;symbol&copy;"
Gheljenor
źródło
2

2 proste metody, które NIE wymagają JQUERY ...

Możesz zakodować wszystkie znaki w swoim ciągu w następujący sposób:

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

Albo po prostu kierować głównych bohaterów martwić &, podziały wierszy, <, >, "i 'tak:

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>

Dave Brown
źródło
2

Przykład ucieczki zwykłego 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;"
Andrew Luca
źródło
3
Odpowiedzi zawierające tylko kod są odradzane, ponieważ nie wyjaśniają, w jaki sposób rozwiązują problem. Zaktualizuj swoją odpowiedź, aby wyjaśnić, w jaki sposób poprawia się ona w stosunku do innych zaakceptowanych i ocenionych odpowiedzi na to pytanie. To pytanie ma również 9 lat, Twoje wysiłki byłyby bardziej doceniane przez użytkowników, którzy mieli ostatnio pytania bez odpowiedzi. Proszę przejrzeć Jak napisać dobrą odpowiedź .
FluffyKitten
1
@FluffyKitten to wyjątkowo ładnie napisany post na blogu o zaletach i wadach takiej funkcji, który szczegółowo wyjaśnia wszystko, co chciałbyś wiedzieć :) shebang.brandonmintern.com/…
db306
@ db306 Odpowiedź została oflagowana jako niska jakość, ponieważ odpowiedź tylko w kodzie nie spełnia wytycznych przepełnienia stosu - zobacz Jak napisać dobrą odpowiedź . Mój komentarz został dodany podczas procesu przeglądu, aby wyjaśnić, co jest wymagane, aby go poprawić, tj. Odpowiedź musi zostać zaktualizowana, aby wyjaśnić, co robi kod i jak poprawia istniejące odpowiedzi. Pozytywne opinie pochodzą od innych recenzentów, którzy popierają to. Dodanie zewnętrznego linku do komentarzy nadal nie spełnia wytycznych SO. Zamiast tego Andrew musi podać odpowiednie informacje bezpośrednio w swojej odpowiedzi.
FluffyKitten
Pamiętaj, że brandonmintern DOT com wygasł i jest teraz zaparkowany. Nowy adres shebang to shebang.mintern.net/foolproof-html-escaping-in-javascript/.
Brandon
0
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);
}
Katharapu Ramana
źródło
0
function htmlDecode(t){
   if (t) return $('<div />').html(t).text();
}

działa jak marzenie

d -_- b
źródło
tekst usuwa tagi html, ale $ ('<div />'). html (t) .html (); działa
Bass Jobsen
0

Ta odpowiedź zawiera jQuery i normalne metody JS, ale jest najkrótsza bez użycia DOM:

unescape(escape("It's > 20% less complicated this way."))

Ciąg znaków ucieczki: It%27s%20%3E%2020%25%20less%20complicated%20this%20way.

Jeśli ci przeszkadzają spacje, spróbuj:

unescape(escape("It's > 20% less complicated this way.").replace(/%20/g, " "))

Ciąg znaków ucieczki: It%27s %3E 20%25 less complicated this way.

Niestety escape()funkcja ta była przestarzała w JavaScript 1.5 . encodeURI()lub encodeURIComponent()są alternatywami, ale ignorują ', więc ostatni wiersz kodu zamieniłby się w to:

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

Wszystkie główne przeglądarki nadal obsługują krótki kod, a biorąc pod uwagę liczbę starych stron internetowych, wątpię, aby wkrótce się to zmieniło.

Cees Timmerman
źródło
Dotyczy to kodowania adresów URL. Pytanie dotyczyło ucieczki HTML, która jest zupełnie inna.
thelem
@ thelem, nie jeśli ciągi są osadzone w tablicach JavaScript osadzonych w HTML, ale zgadzam się, że chodziło o zwykłe ucieczkę HTML, dzięki czemu może być natychmiast wyświetlane jako tekst.
Cees Timmerman
0

ES6 jeden liner do rozwiązania z mustache.js

const escapeHTML = str => (str+'').replace(/[&<>"'`=\/]/g, s => ({'&': '&amp;','<': '&lt;','>': '&gt;','"': '&quot;',"'": '&#39;','/': '&#x2F;','`': '&#x60;','=': '&#x3D;'})[s]);
kurczaki
źródło
-2

Jeśli zapisujesz te informacje w bazie danych , nie można uciec HTML za pomocą skryptu po stronie klienta , należy to zrobić na serwerze . W przeciwnym razie łatwo obejść ochronę XSS.

Aby wyrazić się jasno, oto przykład wykorzystujący jedną z odpowiedzi:

Załóżmy, że używasz funkcji escapeHtml, aby uciec z kodu HTML od komentarza na blogu, a następnie opublikować go na serwerze.

var entityMap = {
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    '"': '&quot;',
    "'": '&#39;',
    "/": '&#x2F;'
  };

  function escapeHtml(string) {
    return String(string).replace(/[&<>"'\/]/g, function (s) {
      return entityMap[s];
    });
  }

Użytkownik może:

  • Edytuj parametry żądania POST i zamień komentarz na kod javascript.
  • Zastąp funkcję escapeHtml za pomocą konsoli przeglądarki.

Jeśli użytkownik wklei ten fragment w konsoli, pominie sprawdzanie poprawności XSS:

function escapeHtml(string){
   return string
}
Kauê Gimenes
źródło
Nie zgadzam się. Aby ominąć tę ochronę XSS, musisz użyć ataku XSS (wstrzyknięcie skryptu, który wyłącza ucieczkę), czyli tego, co faktycznie blokujesz. W niektórych przypadkach bardziej odpowiednie jest ucieczka na kliencie, na przykład jeśli dane pochodzą z interfejsu API REST, który musi zwrócić standardowy JSON.
PaleAle
@Qualcuno Jeśli przeprowadzasz tę weryfikację w kliencie i publikujesz te informacje na serwerze, ufając, że została ona zweryfikowana, użytkownik może po prostu edytować żądanie, a skrypt zostanie zapisany w bazie danych.
Kauê Gimenes
@Qualcuno Podałem kilka przykładów, aby wyjaśnić mój punkt widzenia.
Kauê Gimenes
1
Pytanie dotyczyło ucieczki ciągów otrzymanych z serwera w celu wyświetlenia ich w przeglądarce. To, co mówisz, dotyczy ucieczki ciągów przed przesłaniem ich na serwer, co jest inną rzeczą (chociaż masz rację, i wraca do starej reguły, która nigdy nie ślepo przyjmuje żadnych informacji od klienta )
ItalyPaleAle
@Qualcuno To popularne pytanie w Stackoverflow i uważam, że jest to ważna kwestia do omówienia. Właśnie dlatego odpowiedziałem.
Kauê Gimenes
-2

Wszystkie rozwiązania są bezużyteczne, jeśli dont zapobiec ponownemu ucieczki, np większość rozwiązań byłoby zachować uciekając &się &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] + ";";
        }
    ) : "";
};
C Nimmanant
źródło
4
Nazywa się to podwójnym ucieczką i należy to naprawić, upewniając się, że dane wejściowe nie są jeszcze ucieczkowe. Co jeśli chcesz dosłownie pokazać & lt; do użytkownika? A może tekst zostanie ponownie wykorzystany w innym miejscu i zależy od tego, czy zdarzyło się ucieczka?
thelem