Posso escapar de caracteres especiais html em javascript?

201

Eu quero exibir um texto em HTML por uma função javascript. Como posso escapar caracteres especiais html em JS? Existe uma API?

fernando123
fonte
11
Isso não é uma duplicata, pois esta pergunta não pergunta sobre o jQuery. Estou interessado apenas em um presente, uma vez que não usar jQuery ...
lvella
4
possível duplicata do equivalente HtmlSpecialChars em Javascript?
Bergi 07/08/2013

Respostas:

330
function escapeHtml(unsafe) {
    return unsafe
         .replace(/&/g, "&")
         .replace(/</g, "&lt;")
         .replace(/>/g, "&gt;")
         .replace(/"/g, "&quot;")
         .replace(/'/g, "&#039;");
 }
bjornd
fonte
11
Por que "& # 039;" e não "" ?
sereda
36
porque: stackoverflow.com/questions/2083754/…
Shreyans 27/03
2
Penso que expressões regulares em replace()chamadas são desnecessárias. Seqüências de caracteres simples de caracteres antigos simples também serviriam.
Jamix
22
@jamix Você não pode fazer uma substituição global por strings brutas, enquanto os modernos mecanismos de navegador otimizam bastante a expressão regular simples.
bjornd
5
existe alguma API padrão ou esta é a única maneira?
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
fonte
Trabalhando aqui, mas não trabalhando para mim offline no navegador
48

Você pode usar a .text()função do jQuery .

Por exemplo:

http://jsfiddle.net/9H6Ch/

Na documentação do jQuery referente à .text()função:

Precisamos estar cientes de que esse método escapa à string fornecida conforme necessário para que seja renderizada corretamente em HTML. Para fazer isso, ele chama o método DOM .createTextNode (), não interpreta a sequência como HTML.

As versões anteriores da documentação do jQuery escreveram da seguinte maneira ( ênfase adicionada ):

Precisamos estar cientes de que esse método escapa à string fornecida conforme necessário para que seja renderizada corretamente em HTML. Para fazer isso, ele chama o método DOM .createTextNode (), que substitui caracteres especiais pelos seus equivalentes de entidade HTML (como & lt; for <).

jeremysawesome
fonte
3
Você ainda pode usá-lo em um novo elemento se você quiser apenas converter assim: const str = "foo<>'\"&"; $('<div>').text(str).html()rendimentosfoo&lt;&gt;'"&amp;
amoebe
28

Acho que encontrei a maneira correta de fazer isso ...

// 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
fonte
Eu aprendi algo novo sobre HTML hoje. w3schools.com/jsref/met_document_createtextnode.asp .
Sellorio 27/06
1
Esteja ciente de que o conteúdo do nó de texto não é escapado se você tentar acessá-lo assim:document.createTextNode("<script>alert('Attack!')</script>").textContent
maechler
Esta é a maneira correta se tudo o que você está fazendo é definir texto. Isso também é textContent, mas aparentemente não é bem suportado. Isso não funcionará, no entanto, se você estiver construindo uma string com algumas partes de texto com algum html, precisará escapar ainda.
Jgmjgm 16/10/19
20

Esta é, de longe, a maneira mais rápida que eu já vi. Além disso, ele faz tudo sem adicionar, remover ou alterar elementos na página.

function escapeHTML(unsafeText) {
    let div = document.createElement('div');
    div.innerText = unsafeText;
    return div.innerHTML;
}
arjunpat
fonte
7
Aviso: não escapa aspas, portanto você não pode usar a saída dentro dos valores de atributo no código HTML. Por exemplo var divCode = '<div data-title="' + escapeHTML('Jerry "Bull" Winston') + '">Div content</div>', produzirá HTML inválido!
Izogfif 17/07/19
17

Foi interessante encontrar uma solução melhor:

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

Não analiso >porque não quebra o código XML / HTML no resultado.

Aqui estão os benchmarks: http://jsperf.com/regexpairs Além disso, criei uma escapefunção universal : http://jsperf.com/regexpairs2

iegik
fonte
1
É interessante ver que o uso do comutador é significativamente mais rápido que o mapa. Eu não esperava isso! Obrigado por compartilhar!
Peter T.
Há muito mais caracteres unicode do que você poderia codificar e levar em consideração. Eu não recomendaria este método manual.
vsync 13/06
Por que você escaparia de caracteres de vários bytes? Basta usar UTF-8 em qualquer lugar.
Neonit
4
Ignorar> pode potencialmente quebrar o código. Você deve ter em mente que dentro do <> também há html. Nesse caso, pular> será interrompido. Se você estiver escapando apenas entre as tags, provavelmente precisará apenas de escape <e &.
Jgmjgm #
8

A maneira mais concisa e com melhor desempenho de exibir texto não codificado é usar textContentproperty.

Mais rápido que usar innerHTML. E isso sem levar em conta escapar de sobrecarga.

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

do utilizador
fonte
@ZzZombo, é completamente normal que ele não funcione com tags de estilo e script. Ao adicionar conteúdo a eles, você adiciona código , não texto , e usa o innerHTML nesse caso. Além disso, você não precisa escapar, essas são duas tags especiais que não são analisadas como HTML. Ao analisar, seu conteúdo é tratado como texto até que a sequência de fechamento </seja atendida.
usuário
6

Os elementos DOM suportam a conversão de texto em HTML, atribuindo a innerText . innerText não é uma função, mas atribuir a ela funciona como se o texto tivesse escapado.

document.querySelectorAll('#id')[0].innerText = 'unsafe " String >><>';
teknopaul
fonte
1
Pelo menos no Chrome, a atribuição de texto <br>de múltiplas linhas adiciona elementos no lugar de novas linhas, que podem quebrar certos elementos, como estilos ou scripts. O createTextNodenão é propenso a esse problema.
ZzZombo
1
innerTexttem alguns problemas de legado / especificação. Melhor usar textContent.
Roy Tinker
3

Você pode codificar todos os caracteres da sua string:

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

Ou apenas alveje os personagens principais com os quais se preocupar (&, inebreaks, <,>, "e ') como:

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
fonte
Escrever sua própria função de escape geralmente é uma má ideia. Outras respostas são melhores nesse sentido.
1113
2

Uma linha (para ES6 +):

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

Para versões mais antigas:

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

Me deparei com esse problema ao criar uma estrutura DOM. Esta pergunta me ajudou a resolvê-lo. Eu queria usar uma divisa dupla como separador de caminho, mas o acréscimo de um novo nó de texto resultou diretamente na exibição do código de caractere de escape, em vez do próprio caractere:

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

Se você já usa módulos no seu aplicativo, pode usar o módulo escape-html .

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

Tente isso, usando a prototype.jsbiblioteca:

string.escapeHTML();

Experimente uma demonstração

Por sorte
fonte
5
Isso requer a biblioteca "prototype.js", que não era aparente imediatamente na demonstração. :(
audiodude
-4

Eu vim com esta solução.

Vamos supor que queremos adicionar algum html ao elemento com dados não seguros do usuário ou banco de dados.

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

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

element.html(html);

Não é seguro contra ataques XSS. Agora adicione isso.

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

Então é

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

Para mim, isso é muito mais fácil do que usar .replace()e será removido !!! todas as tags html possíveis (espero).

Kostiantyn
fonte
Se for uma idéia perigosa, ele analisa a String HTML insegura como HTML; se o elemento fosse anexado ao DOM, ele sairia. use .innerText.
precisa saber é o seguinte
Isso não é seguro. Ele se converte &lt;script&gt;em <script>.
fgb