¿Puedo escapar de caracteres especiales html en javascript?

201

Quiero mostrar un texto a HTML mediante una función de JavaScript. ¿Cómo puedo escapar de caracteres especiales html en JS? ¿Hay una API?

fernando123
fuente
11
Esto no es un duplicado, ya que esta pregunta no hace preguntas sobre jQuery. Estoy interesado solo en este, ya que no uso jQuery ...
lvella
44
posible duplicado de HtmlSpecialChars equivalente en Javascript?
Bergi

Respuestas:

330
function escapeHtml(unsafe) {
    return unsafe
         .replace(/&/g, "&")
         .replace(/</g, "&lt;")
         .replace(/>/g, "&gt;")
         .replace(/"/g, "&quot;")
         .replace(/'/g, "&#039;");
 }
bjornd
fuente
11
¿Por qué "& # 039;" y no "& apos;" ?
sereda el
2
Creo que las expresiones regulares en las replace()llamadas son innecesarias. Las cadenas simples de un solo carácter funcionarían igual de bien.
jamix
22
@jamix No puede hacer un reemplazo global con cadenas sin procesar, mientras que los motores de navegador modernos optimizan la expresión regular simple bastante bien.
bjornd
55
¿Hay alguna API estándar o esta es la única manera?
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
fuente
Trabajando aquí pero no trabajando para mí sin conexión en el navegador
48

Puedes usar la función de jQuery.text() .

Por ejemplo:

http://jsfiddle.net/9H6Ch/

De la documentación de jQuery con respecto a la .text()función:

Debemos tener en cuenta que este método escapa a la cadena proporcionada según sea necesario para que se procese correctamente en HTML. Para hacerlo, llama al método DOM .createTextNode (), no interpreta la cadena como HTML.

Las versiones anteriores de la documentación de jQuery estaban redactadas de esta manera ( énfasis agregado ):

Debemos tener en cuenta que este método escapa a la cadena proporcionada según sea necesario para que se procese correctamente en HTML. Para hacerlo, llama al método DOM .createTextNode (), que reemplaza caracteres especiales con sus equivalentes de entidad HTML (como & lt; para <).

jeremysawesome
fuente
3
Incluso se puede utilizar en un elemento fresco, si lo que desea es convertido de esta manera: const str = "foo<>'\"&"; $('<div>').text(str).html()los rendimientosfoo&lt;&gt;'"&amp;
amoebe
28

Creo que encontré la forma correcta de hacerlo ...

// 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
fuente
Aprendí algo nuevo sobre HTML hoy. w3schools.com/jsref/met_document_createtextnode.asp .
Sellorio
1
Tenga en cuenta que el contenido del nodo de texto no se escapa si intenta acceder a él de esta manera:document.createTextNode("<script>alert('Attack!')</script>").textContent
maechler
Esta es la forma correcta si todo lo que está haciendo es configurar el texto. Eso también es textContent pero aparentemente no está bien soportado. Sin embargo, esto no funcionará si está creando una cadena con algunas partes de texto en html, entonces aún debe escapar.
jgmjgm
21

Esta es, con mucho, la forma más rápida en que lo he visto hacer. Además, lo hace todo sin agregar, eliminar o cambiar elementos en la página.

function escapeHTML(unsafeText) {
    let div = document.createElement('div');
    div.innerText = unsafeText;
    return div.innerHTML;
}
arjunpat
fuente
77
Advertencia: no escapa a las comillas, por lo que no puede usar la salida dentro de los valores de atributo en el código HTML. Por ejemplo, var divCode = '<div data-title="' + escapeHTML('Jerry "Bull" Winston') + '">Div content</div>'generará HTML no válido.
izogfif
17

Fue interesante encontrar una mejor solución:

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

Yo no analizo > porque no rompe el código XML / HTML en el resultado.

Aquí están los puntos de referencia: http://jsperf.com/regexpairs Además, creé una escapefunción universal : http://jsperf.com/regexpairs2

iegik
fuente
1
Es interesante ver que usar el interruptor es significativamente más rápido que el mapa. ¡No esperaba esto! ¡Gracias por compartir!
Peter T.
Hay muchos más caracteres Unicode de los que podría codificar y tener en cuenta. No recomendaría este método manual en absoluto.
vsync
¿Por qué escaparías de los caracteres de varios bytes? Simplemente use UTF-8 en todas partes.
Neonit
44
Omitir> puede potencialmente romper el código. Debes tener en cuenta que dentro de <> también hay html. En ese caso, saltar> se romperá. Si solo está escapando entre etiquetas, entonces probablemente solo necesite escapar <y &.
jgmjgm
8

La forma más concisa y eficaz de mostrar texto no codificado es usar la textContentpropiedad.

Más rápido que usar innerHTML. Y eso sin tener en cuenta los gastos generales de escape.

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

usuario
fuente
@ZzZombo, es completamente normal que no funcione con etiquetas de estilo y script. Cuando les agrega contenido, agrega código , no texto , use innerHTML en este caso. Además, no necesita escapar, son dos etiquetas especiales que no se analizan como HTML. Al analizar, su contenido se trata como texto hasta que </se cumpla la secuencia de cierre .
usuario
6

Los elementos DOM admiten la conversión de texto a HTML mediante la asignación a innerText . innerText no es una función, pero su asignación funciona como si se escapara el texto.

document.querySelectorAll('#id')[0].innerText = 'unsafe " String >><>';
teknopaul
fuente
1
Al menos en Chrome, la asignación de texto multilínea agrega <br>elementos en lugar de nuevas líneas, que pueden romper ciertos elementos, como estilos o scripts. El createTextNodeno es propenso a este problema.
ZzZombo
1
innerTexttiene algunos problemas de legado / especificaciones. Mejor de usar textContent.
Roy Tinker
3

Puedes codificar todos los caracteres de tu cadena:

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

O simplemente apunte a los personajes principales de los que preocuparse (&, inebreaks, <,>, "y ') 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
fuente
Escribir su propia función de escape es generalmente una mala idea. Otras respuestas son mejores en este sentido.
Jannis
2

Una línea (para ES6 +):

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

Para versiones anteriores:

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

Encontré este problema al construir una estructura DOM. Esta pregunta me ayudó a resolverlo. Quería usar un doble chevron como separador de ruta, pero agregar un nuevo nodo de texto resultó directamente en la visualización del código de caracteres escapado, en lugar del carácter en sí:

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

Si ya usa módulos en su aplicación, puede usar el módulo escape-html .

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

Prueba esto, usando la prototype.jsbiblioteca:

string.escapeHTML();

Prueba una demo

Suerte
fuente
55
Esto requiere la biblioteca "prototype.js", que no fue inmediatamente aparente en la demostración. :(
audiodude
-4

Se me ocurrió esta solución.

Supongamos que queremos agregar algo de HTML al elemento con datos inseguros del usuario o la base de datos.

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

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

element.html(html);

No es seguro contra los ataques XSS. Ahora agregue esto.

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

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

¡Para mí, esto es mucho más fácil que usarlo .replace()y lo eliminará! todas las posibles etiquetas html (espero).

Kostiantyn
fuente
Esta es una idea peligrosa, analiza la Cadena HTML insegura como HTML, si el elemento se adjunta al DOM se ejecutaría. use .innerText en su lugar.
teknopaul
Esto no es seguro. Se convierte &lt;script&gt;en <script>.
fgb