Escapando cadeias HTML com jQuery

609

Alguém sabe uma maneira fácil de escapar HTML de seqüências de caracteres no jQuery ? Eu preciso ser capaz de passar uma string arbitrária e fazer com que ela escape corretamente para exibição em uma página HTML (evitando ataques de injeção de JavaScript / HTML). Tenho certeza de que é possível estender o jQuery para fazer isso, mas não sei o suficiente sobre a estrutura no momento para fazer isso.

Página
fonte
Veja também perf: jsperf.com/…
Christophe Roussy

Respostas:

445

Como você está usando jQuery , você pode apenas definir a textpropriedade do elemento :

// 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
fonte
57
Você perdeu o ponto em que precisa acessar $ ("div.someClass"). Html () para obter a versão escapada.
Morten Christiansen
16
Isso não é seguro para vários navegadores se a sua string tiver espaços em branco e \ n \ r \ t caracteres nela
nivcaner
20
@travis Isso está documentado no site do jQuery: "Devido a variações nos analisadores HTML em diferentes navegadores, o texto retornado pode variar em novas linhas e outros espaços em branco". api.jquery.com/text
geofflee 24/03
3
@mklement se você já está usando essa solução, você não terá quaisquer problemas com isso fazendo algo como: $(element2).attr("some-attr", $(element1).html());Veja este exemplo: jsbin.com/atibig/1/edit
travis
16
Isso não escapa aspas e aspas duplas, o que é ruim! wonko.com/post/html-escaping
Lior
601

Há também a solução do 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];
  });
}
Tom Gruner
fonte
7
Observe que, curiosamente, 'é mapeado para uma entidade com um formato decimal , enquanto /usa o formato hexadecimal .
usar o seguinte comando
43
Essa deve ser a resposta aceita - é simples, eficiente, não requer dependências e faz exatamente o que se destina, sem hacks obscuros.
Lorefnon
6
qual é a orientação sobre a conversão \npara <br>?
amwinter
2
Aqui está um link atualizado à fonte: github.com/janl/mustache.js/blob/...
mjackson
8
@amwinter, estendi o script acima adicionando "\ n": '<br>' ao mapa da entidade e atualizei o regexp para / [& <> "'\ /] | [\ n] / g
walv
182
$('<div/>').text('This is fun & stuff').html(); // "This is fun &amp; stuff"

Fonte: http://debuggable.com/posts/encode-html-entities-with-jquery:480f4dd6-13cc-4ce9-8071-4710cbdd56cb

Henrik N
fonte
11
Conforme mencionado na resposta acima, não é garantido que esta solução preserve espaços em branco.
geofflee
47
Note-se que isso não faz nada para escapar de aspas simples ou duplas. se você planeja colocar o valor em um atributo HTML, isso pode ser um problema.
Kip
6
@Kip: @travis descobriu que o attr()método do jQuery (a partir de pelo menos 1.8.3) faz sua própria codificação, para que as strings não codificadas possam ser passadas diretamente ; Por exemplo:$('<div/>').attr('test-attr', '\'Tis "fun" & stuff')[0].outerHTML
mklement0:
1
@tarekahf Isso é estranho. Qual versão do jQuery você está usando? O código de exemplo funciona se você o copiar e colar literalmente? Funciona bem com o jQuery (3.1.0) mais recente aqui: jsbin.com/fazimigayo/1/edit?html,js,console,output (e também deve funcionar em todas as versões anteriores)
Henrik N
1
@tarekahf $('<div/>')cria um novo divelemento que não está anexado ao DOM. Portanto, não mudará nenhum elemento existente. É um pouco confuso como jQuery usa a mesma $()função tanto para encontrar elementos ( $('div')) e para criá-los, e para mais algumas coisas além disso ... :)
Henrik N
61

Se você está fugindo para HTML, existem apenas três que eu posso pensar que seriam realmente necessários:

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

Dependendo do seu caso de uso, você também pode precisar de fazer coisas como "a &quot;. Se a lista fosse grande o suficiente, eu apenas usaria uma matriz:

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() escapará apenas para URLs, não para HTML.

tghw
fonte
13
Essa expressão regular produzirá resultados estranhos se o HTML em questão já tiver escapado de entidades. Por exemplo, escapando "Tom & amp; Jerry" irá produzir "Tom & amp; amp; Jerry"
Ryan
12
Por favor, use varpara declarar itemlocalmente; de qualquer maneira, não use um for … inloop quando estiver percorrendo um array! Use um forloop comum em seu lugar. Oh, e é encodeURIComponent, não escapeURIComponent.
Marcel Korpel
3
Se você estiver trabalhando com atributos de tag, também precisará escapar de aspas e / ou aspas duplas. A documentação do PHP para htmlspecialchars contém uma lista útil de conversões que ele realiza. php.net/htmlspecialchars
geofflee 24/03
4
Apenas um lembrete gentil para novas pessoas, não use isso se você pretende ter caracteres não-ingleses em algum lugar em seu site ... Obviamente, isso não vai fazer por causa de caracteres com acentos como 'E': &eacute; Aqui está uma lista de entidades html, para referência: w3schools.com/tags/ref_entities.asp
LoganWolfer
11
@ Ryan: Embora valha a pena ressaltar que esta solução não lida corretamente com seqüências de caracteres codificadas, também não vale nada que o mesmo se aplique à maioria das soluções - possivelmente todas - nesta página.
usar o seguinte comando
37

Fácil o suficiente para usar sublinhado:

_.escape(string) 

O Underscore é uma biblioteca de utilitários que fornece muitos recursos que o js nativo não fornece. Há também o lodash, que é a mesma API que o sublinhado, mas foi reescrito para ter melhor desempenho.

chovy
fonte
36

Eu escrevi uma pequena função que faz isso. Ele só escapa ", &, <e >(mas geralmente isso é tudo que você precisa de qualquer maneira). É um pouco mais elegante do que as soluções propostas anteriormente, pois usa apenas uma .replace() para fazer toda a conversão. ( EDIÇÃO 2: complexidade do código reduzida, tornando a função ainda menor e mais organizada, se você estiver curioso sobre o código original, veja o final desta resposta.)

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

Isso é Javascript simples, sem jQuery usado.

Escapando /e 'também

Edite em resposta ao comentário de mklement .

A função acima pode ser facilmente expandida para incluir qualquer caractere. Para especificar mais caracteres para escapar, basta inseri-los na classe de caracteres na expressão regular (ou seja, dentro da /[...]/g) e como uma entrada no chrobjeto. ( EDIT 2: Também reduziu esta função, da mesma maneira.)

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

Observe o uso acima de &#39;para apóstrofo (a entidade simbólica &apos;poderia ter sido usado em vez disso - ele é definido em XML, mas não foi originalmente incluído no HTML especificação e pode, portanto, não ser suportado por todos os navegadores Veja:. Artigo da Wikipedia sobre codificação de caracteres em HTML ) Também me lembro de ler em algum lugar que o uso de entidades decimais é mais amplamente suportado do que o hexadecimal, mas não consigo encontrar a fonte para isso agora. (E não pode haver muitos navegadores por aí que não suportem entidades hexadecimais.)

Nota: Adicionar /e 'à lista de caracteres de escape não é tão útil, pois eles não têm nenhum significado especial em HTML e não precisam ser escapados.

escapeHtmlFunção original

EDIT 2: A função original usava uma variável ( chr) para armazenar o objeto necessário para o .replace()retorno de chamada. Essa variável também precisava de uma função anônima extra para fazer o escopo, tornando a função (desnecessariamente) um pouco maior e mais complexa.

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

Eu não testei qual das duas versões é mais rápida. Se o fizer, sinta-se à vontade para adicionar informações e links sobre isso aqui.

zrajm
fonte
Obrigado por reservar um tempo, @Zrajm. Bom argumento sobre não precisar fugir; Alguma idéia do porquê dos dois mustache.jse underscore.jsfazê-lo? Falando nisso, ele reconhece apenas as entidades numéricas (representando 'e /'), na forma hexadecimal maiúscula , quando não está escapando. Assim, o texto escapou mustache.js- o que curiosamente usa uma mistura de hexadecimal. e formatos decimais - não seria corretamente desviado em underscore.js. Gostaria de saber como outras bibliotecas populares lidam com isso.
usar o seguinte comando
1
A forma hexagonal caso mais baixo é a forma mais suportado, de modo que é (provavelmente) o forma que as bibliotecas devem converter a . (É claro que ambas as formas devem funcionar ao converter de .) - Os apóstrofos 'têm algum tipo de função reservada em XML (e, portanto, XHTML, eu imagino?), E é por isso que XML (mas não HTML) tem a entidade nomeada &apos;. Exatamente por que ou de que maneira é "reservado" eu não sei. - Cortes são especiais em URLs, mas isso não realmente garante-los para inclusão em escapar HTML (como codificação de URL é algo completamente diferente).
Zrajm
Re &apos;: correto: uso seguro apenas em XHTML ; direto da boca da fonte da multidão - ênfase minha: "(...) lido por um processador HTML em conformidade , (...) o uso de & '; ou referências de entidade personalizadas podem não ser suportadas (...)" - na prática : navegadores modernos oferecem suporte mesmo em HTML . Re caso em números hexadecimais. (mesma fonte; grifo meu): "O x deve estar em minúsculas nos documentos XML. [...] O hhhh pode combinar maiúsculas e minúsculas, embora maiúsculas seja o estilo usual ." Deixa-nos imaginar quem decidiu codificar barras; talvez realmente apenas uma confusão entre URI e codificação HTML?
usar o seguinte comando
2
Considerações finais: parece que a codificação /não é necessária, mas a codificação 'ainda parece útil para lidar com segurança no caso em que uma string codificada é usada como um valor de atributo entre aspas simples .
usar o seguinte código
Ambos são lentos. A solução mais rápida por uma margem de dois dígitos é uma série de substituições que passam cadeias de caracteres em vez de funções.
11117 Adam Adgetgett
34

Percebo como estou atrasado para esta festa, mas tenho uma solução muito fácil que não requer jQuery.

escaped = new Option(unescaped).innerHTML;

Edit: Isso não escapa aspas. O único caso em que as aspas precisariam ser escapadas é se o conteúdo será colado inline em um atributo dentro de uma string HTML. É difícil para mim imaginar um caso em que fazer isso seria um bom design.

Edit 3: Para a solução mais rápida, verifique a resposta acima em Saram. Este é o mais curto.

Adam Leggett
fonte
Isso não muda as aspas - pelo menos agora no Firefox 52.
getsetbro
1
O escape de aspas é apenas funcionalmente relevante nos atributos. Como estamos escapando <e >, também não há benefício em escapar das aspas, a menos que a intenção do conteúdo gerado seja entrar em um atributo.
precisa
31

Aqui está uma função JavaScript limpa e clara. Ele escapará de textos como "alguns <muitos" para "alguns poucos".

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
fonte
28

Após os últimos testes, posso recomendar a solução javaScript (DOM) nativa mais rápida e completamente compatível com o navegador :

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

Se você repetir várias vezes, poderá fazê-lo com variáveis ​​preparadas uma vez:

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

Olhe para o meu desempenho final comparação ( questão da pilha ).

Saram
fonte
2
É necessário usar dois nós? Como sobre apenas um:var p = document.createElement('p'); p.textContent = html; return p.innerHTML;
Dan Dascalescu
2
@ DanDascalescu: De acordo com o MDN , a textContentfunção é suportada apenas pelo Chrome 1+, Firefox 2, IE9, Opera 9.64 e Safari 3 (os dois últimos anotados "possivelmente antes"). Isso quebraria a alegação de "OP completamente compatível com vários navegadores".
Zb226
p.innerText = html; return p.innerHTML
Bekim Bacaj
24

Tente Underscore.string lib, ele funciona com jQuery.

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

resultado:

'&lt;div&gt;Blah blah blah&lt;/div&gt;'
Nikita Koksharov
fonte
20
A principal biblioteca de sublinhado agora tem uma _.escape()função de utilitário.
Codeape
15

Aprimorei o exemplo mustache.js adicionando o escapeHTML()método ao objeto string.

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

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

Dessa forma, é bastante fácil de usar "Some <text>, more Text&Text".escapeHTML()

Jeena
fonte
Útil, mas também mudei __entityMappara o escopo local da função. E envolveu tudo isso emif (typeof String.prototype.escapeHTML !== 'function'){...}
FlameStorm
15

escape()e unescape()se destina a codificar / decodificar seqüências de caracteres para URLs, não HTML.

Na verdade, eu uso o seguinte snippet para executar o truque que não requer nenhuma estrutura:

var escapedHtml = html.replace(/&/g, '&amp;')
                      .replace(/>/g, '&gt;')
                      .replace(/</g, '&lt;')
                      .replace(/"/g, '&quot;')
                      .replace(/'/g, '&apos;');
NicolasBernier
fonte
Se você tiver "s, precisará adicionar pelo menos 'e `` à briga. Esses são realmente necessários apenas para dados de tags de string dentro de elementos em html. Para os próprios dados html (tags externas), apenas os três primeiros são necessários.
Marius
10

Se você tiver underscore.js, use _.escape(mais eficiente que o método jQuery publicado acima):

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

Se você estiver seguindo a rota regex, há um erro no exemplo do tghw acima.

<!-- 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
fonte
2
Eu acredito que deveria ser para (var item em findReplace) {escaped = escaped.replace (findReplace [item] [0], findReplace [item] [1]); }
Chris Stephens
5

Este é um bom exemplo seguro ...

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
fonte
4
Que tipos de exceções você está suprimindo lá?
Stefan Majewsky
3

Você pode fazer isso facilmente com vanilla js.

Basta adicionar um nó de texto ao documento. Será escapado pelo navegador.

var escaped = document.createTextNode("<HTML TO/ESCAPE/>")
document.getElementById("[PARENT_NODE]").appendChild(escaped)
raam86
fonte
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));
    };
})();

Sem variáveis ​​globais, alguma otimização de memória. Uso:

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

O resultado é:

"some&lt;tag&gt;and&amp;symbol&copy;"
Gheljenor
fonte
2

2 métodos simples que não requerem consulta ...

Você pode codificar todos os caracteres em sua string assim:

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

Ou apenas como alvo os principais personagens que se preocupar &, quebras de linha, <, >, "e 'como:

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
fonte
2

Exemplo simples de escape de 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
fonte
3
As respostas somente de código são desencorajadas porque não explicam como resolvem o problema. Atualize sua resposta para explicar como isso melhora as outras respostas aceitas e aprovadas anteriormente que esta pergunta já possui. Além disso, se essa pergunta tiver 9 anos, seus esforços serão mais apreciados pelos usuários que têm perguntas não respondidas recentes. Revise Como escrevo uma boa resposta .
FluffyKitten #
1
@FluffyKitten aqui está um um post extremamente nicly escrito sobre as vantagens e desvantagens de tal função que explica em detalhes tudo o que você gostaria de saber :) shebang.brandonmintern.com/...
db306
@ db306 A resposta foi sinalizada como de baixa qualidade porque a resposta somente de código não atende às diretrizes de estouro de pilha - consulte Como escrever uma boa resposta . Meu comentário foi adicionado durante o processo de revisão para explicar o que é necessário para melhorá-lo, ou seja, a resposta precisa ser atualizada para explicar o que o código faz e como ele melhora as respostas existentes. Os votos positivos são de outros revisores para endossar isso. A adição de um link externo aos comentários ainda não atende às diretrizes de SO. Em vez disso, Andrew precisa incluir as informações relevantes diretamente em sua resposta.
FluffyKitten #
Observe que brandonmintern DOT com expirou e agora está estacionado. O novo endereço shebang é 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
fonte
0
function htmlDecode(t){
   if (t) return $('<div />').html(t).text();
}

Funciona como um encanto

d -_- b
fonte
o texto remove as tags html, mas $ ('<div />'). html (t) .html (); funciona
Bass Jobsen
0

Esta resposta fornece os métodos jQuery e JS normais, mas é mais curta sem usar o DOM:

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

String com escape: It%27s%20%3E%2020%25%20less%20complicated%20this%20way.

Se os espaços escapados o incomodarem, tente:

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

String com escape: It%27s %3E 20%25 less complicated this way.

Infelizmente, a escape()função foi descontinuada no JavaScript versão 1.5 . encodeURI()ou encodeURIComponent()são alternativas, mas eles ignoram ', portanto a última linha de código se tornaria isso:

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

Todos os principais navegadores ainda suportam o código curto e, dado o número de sites antigos, duvido que isso mude em breve.

Cees Timmerman
fonte
Isto é para codificação de URL. A pergunta era sobre escape de HTML, o que é muito diferente.
Thelem 15/10
@ thelem, não se as strings estiverem incorporadas em matrizes JavaScript incorporadas em HTML, mas eu concordo que se tratava de escape de HTML simples para que possa ser exibido imediatamente como texto.
Cees Timmerman
0

ES6 one liner para a solução from mustache.js

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

Se você estiver salvando essas informações em um banco de dados , é errado escapar do HTML usando um script do lado do cliente , isso deve ser feito no servidor . Caso contrário, é fácil ignorar sua proteção XSS.

Para deixar claro meu argumento, aqui está um exemplo usando uma das respostas:

Digamos que você esteja usando a função escapeHtml para escapar do Html de um comentário no seu blog e depois publicá-lo no seu servidor.

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

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

O usuário pode:

  • Edite os parâmetros de solicitação POST e substitua o comentário pelo código javascript.
  • Substitua a função escapeHtml usando o console do navegador.

Se o usuário colar esse trecho no console, ele ignorará a validação do XSS:

function escapeHtml(string){
   return string
}
Kauê Gimenes
fonte
Discordo. Para ignorar essa proteção XSS, você teria que usar um ataque XSS (injetando um script que desativa a fuga), que é o que você está realmente bloqueando. Em certos casos, é realmente mais apropriado escapar no cliente, por exemplo, se os dados vierem de uma API REST que precisa retornar JSON padrão.
ItáliaPaleAle
@Qualcuno Se você estiver fazendo essa validação no cliente e postando essas informações no servidor em que foram validadas, o usuário pode simplesmente editar a solicitação e o script será salvo no banco de dados.
Kauê Gimenes
@ Qualcuno eu incluí alguns exemplos para deixar meu argumento mais claro.
Kauê Gimenes
1
A pergunta era sobre como escapar seqüências de caracteres recebidas do servidor para exibi- las no navegador. O que você está dizendo é sobre escapar strings antes de submetê-los ao servidor, que é uma coisa diferente (embora você está certo, lá, e ele vai voltar para a velha regra não aceitar cegamente qualquer entrada do cliente )
ItalyPaleAle
@ Qualcuno Esta é uma pergunta popular no Stackoverflow, e acredito que este seja um ponto importante a ser abordado. Foi por isso que eu respondi.
Kauê Gimenes
-2

Todas as soluções são inúteis se você não evitar re-escape, por exemplo, a maioria das soluções seria manter escapar &para &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
fonte
4
Isso se chama escape duplo e deve ser corrigido, garantindo que os dados de entrada ainda não tenham escapado. E se você quisesse literalmente mostrar & lt; para o usuário? Ou talvez o texto seja reutilizado em outro lugar e dependa da fuga?
Thelem