Escapar de cadenas HTML con jQuery

609

¿Alguien sabe de una manera fácil de escapar de HTML de cadenas en jQuery ? Necesito poder pasar una cadena arbitraria y hacer que se escape correctamente para mostrarla en una página HTML (evitando ataques de inyección de JavaScript / HTML). Estoy seguro de que es posible extender jQuery para hacer esto, pero no sé lo suficiente sobre el marco en este momento para lograr esto.

Página
fuente
Ver también perf: jsperf.com/…
Christophe Roussy

Respuestas:

445

Como está utilizando jQuery , puede establecer la textpropiedad del 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
fuente
57
Te perdiste el punto de que tienes que acceder a $ ("div.someClass"). Html () para obtener la versión escapada.
Morten Christiansen
16
Esto no es segura cruz navegador si la cadena tiene espacios en blanco y \ n \ r \ t caracteres en ella
nivcaner
20
@travis Esto está documentado en el sitio web de jQuery: "Debido a las variaciones en los analizadores HTML en diferentes navegadores, el texto devuelto puede variar en las nuevas líneas y otros espacios en blanco". api.jquery.com/text
geofflee
3
@mklement si ya está utilizando esta solución, no tendrá ningún problema al hacer algo como: $(element2).attr("some-attr", $(element1).html());Vea este ejemplo: jsbin.com/atibig/1/edit
travis
16
¡Esto NO escapa a las comillas y comillas dobles, lo cual es malo! wonko.com/post/html-escaping
Lior
601

También existe la solución de 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
fuente
77
Tenga en cuenta que, curiosamente, 'se asigna a una entidad con un formato decimal , mientras que /utiliza el formato hexadecimal .
mklement0
43
Esta debería ser la respuesta aceptada: es simple, eficiente, no requiere dependencias y hace exactamente lo que se pretende sin hacks oscuros.
lorefnon
66
¿cuál es la orientación sobre la conversión \na <br>?
amwinter
2
Aquí hay un enlace actualizado a la fuente: github.com/janl/mustache.js/blob/…
mjackson
8
@amwinter, extendí el script anterior agregando "\ n": '<br>' al mapa de entidades y actualicé la expresión regular a / [& <> "'\ /] | [\ n] / g
walv
182
$('<div/>').text('This is fun & stuff').html(); // "This is fun &amp; stuff"

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

Henrik N
fuente
11
Como se menciona en la respuesta anterior, no se garantiza que esta solución conserve los espacios en blanco.
geofflee
47
Cabe señalar que esto no hace nada para escapar de comillas simples o dobles. Si planea poner el valor en un atributo HTML, esto puede ser un problema.
Kip
66
@Kip: @travis descubrió que el attr()método de jQuery (a partir de al menos 1.8.3) realiza su propia codificación, de modo que las cadenas sin codificar se pueden pasar directamente ; por ejemplo:$('<div/>').attr('test-attr', '\'Tis "fun" & stuff')[0].outerHTML
mklement0
1
@tarekahf Eso es extraño. ¿Qué versión de jQuery estás usando? ¿Funciona el código de ejemplo si lo copia y pega literalmente? Funciona bien con la última jQuery (3.1.0) aquí: jsbin.com/fazimigayo/1/edit?html,js,console,output (y también debería funcionar en todas las versiones anteriores)
Henrik N
1
@tarekahf $('<div/>')crea un nuevo divelemento que no está adjunto al DOM. Por lo tanto, no cambiará ningún elemento existente. Es un poco confuso cómo jQuery usa la misma $()función tanto para encontrar elementos ( $('div')) como para crearlos, y para algunas cosas más además de ... :)
Henrik N
61

Si está escapando para HTML, solo hay tres que puedo pensar que serían realmente necesarios:

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

Dependiendo de su caso de uso, es posible que también tenga que hacer cosas como "a &quot;. Si la lista se volviera lo suficientemente grande, solo usaría una 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() solo se escapará para las URL, no para HTML.

tghw
fuente
13
Esta expresión regular producirá resultados extraños si el HTML en cuestión ya tiene entidades escapadas. Por ejemplo, escapar de "Tom & amp; Jerry" producirá "Tom & amp; amp; Jerry"
Ryan
12
Utilice varpara declarar itemlocalmente; de todos modos, ¡no uses ningún for … inbucle cuando recorras una matriz! Use un forbucle ordinario en su lugar. Ah, y que es encodeURIComponent, no escapeURIComponent.
Marcel Korpel
3
Si está trabajando con atributos de etiqueta, también necesitará escapar de comillas y / o comillas dobles. La documentación de PHP para htmlspecialchars contiene una lista útil de conversiones que realiza. php.net/htmlspecialchars
geofflee
44
Sólo un recordatorio para la gente nueva especie, no utilice esta opción si la intención de tener caracteres no ingleses en algún lugar de su sitio web ... Es evidente que esto no va a hacer debido a los caracteres acentuados como 'E': &eacute; Aquí hay una lista de entidades html, para referencia: w3schools.com/tags/ref_entities.asp
LoganWolfer
11
@Ryan: Si bien vale la pena señalar que esta solución no maneja las cadenas ya codificadas correctamente, tampoco vale nada que lo mismo se aplique a la mayoría, posiblemente a todas, las soluciones en esta página.
mklement0
37

Suficientemente fácil de usar subrayado:

_.escape(string) 

El subrayado es una biblioteca de utilidades que proporciona muchas características que no proporciona js nativo. También hay lodash, que es la misma API que el subrayado, pero fue reescrito para ser más eficiente .

chovy
fuente
36

Escribí una pequeña y pequeña función que hace esto. Sólo se escapa ", &, <y >(por lo general, pero eso es todo lo que necesita de todos modos). Es un poco más elegante que las soluciones propuestas anteriormente, ya que solo usa una .replace() para hacer toda la conversión. ( EDITAR 2: complejidad de código reducida que hace que la función sea aún más pequeña y ordenada, si tiene curiosidad sobre el código original, vea el final de esta respuesta).

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

Esto es Javascript simple, no se utiliza jQuery.

Escapando /y 'también

Edite en respuesta al comentario de mklement .

La función anterior se puede ampliar fácilmente para incluir cualquier carácter. Para especificar más caracteres para escapar, simplemente insértelos en la clase de caracteres en la expresión regular (es decir, dentro de /[...]/g) y como una entrada en el chrobjeto. ( EDIT 2: también acortó esta función, de la misma manera).

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

Tenga en cuenta el uso anterior de &#39;para apóstrofo (la entidad simbólica &apos;podría haberse utilizado en su lugar; está definida en XML, pero originalmente no se incluyó en la especificación HTML y, por lo tanto, podría no ser compatible con todos los navegadores. Ver: artículo de Wikipedia sobre codificaciones de caracteres HTML ) También recuerdo haber leído en alguna parte que usar entidades decimales es más ampliamente compatible que usar hexadecimal, pero parece que no puedo encontrar la fuente para eso ahora. (Y no puede haber muchos navegadores que no sean compatibles con las entidades hexadecimales).

Nota: Agregar /y 'a la lista de caracteres escapados no es tan útil, ya que no tienen ningún significado especial en HTML y no es necesario que se escapen.

escapeHtmlFunción original

EDIT 2: la función original utilizaba una variable ( chr) para almacenar el objeto necesario para la .replace()devolución de llamada. Esta variable también necesitaba una función anónima adicional para abarcarla, haciendo que la función (innecesariamente) sea un poco más grande y más compleja.

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

No he probado cuál de las dos versiones es más rápida. Si lo hace, no dude en agregar información y enlaces al respecto aquí.

zrajm
fuente
Gracias por tomarse el tiempo, @Zrajm. Buen punto sobre no necesitar escapar; alguna idea de por qué ambos mustache.jsy underscore.jshacerlo? Hablando de este último: sólo reconoce las entidades numéricas (que representan 'y /'), en el hexagonal mayúsculas se forman cuando la ONU se escape. Por lo tanto, el texto escapó mustache.js, que curiosamente usa una mezcla de hexadecimal. y formatos decimales: no estarían correctamente sin escape underscore.js. Me pregunto cómo lidian otras bibliotecas populares con eso.
mklement0
1
La forma hexagonal inferior caso es la forma más compatible, por lo que es (probablemente) la forma en que las bibliotecas deben convertir a . (Por supuesto, ambas formas deben trabajar al convertir a .) - Los apóstrofes 'tienen algún tipo de función reservada en XML, que es la razón XML (pero no HTML) tienen la entidad con nombre (y por lo tanto XHTML, me imagino?) &apos;. No sé exactamente por qué o de qué manera está "reservado". - Las barras diagonales son especiales en las URL, pero eso no significa realmente justifican su inclusión en ellos de escape HTML (como la codificación URL es algo completamente diferente).
zrajm
Re &apos;: correcto: uso seguro solo en XHTML ; directamente de la boca de la fuente de la multitud - énfasis mío: "(...) leído por un procesador HTML conforme , (...) el uso de & apos; o referencias de entidades personalizadas pueden no ser compatibles (...)" - en la práctica : los navegadores modernos lo admiten incluso en HTML . Re case en números hexagonales. (misma fuente; énfasis mío): "La x debe estar en minúsculas en los documentos XML. [...] El hhhh puede mezclar mayúsculas y minúsculas, aunque mayúsculas es el estilo habitual ". Nos deja preguntarnos quién decidió codificar barras; ¿quizás realmente solo una confusión entre la codificación URI y HTML?
mklement0
2
Reflexiones finales: parece que la codificación /no es necesaria, pero la codificación 'aún parece útil para manejar con seguridad el caso en el que se utiliza una cadena codificada como un valor de atributo encerrado entre comillas simples .
mklement0
Ambos son lentos. La solución más rápida por un margen de dos dígitos es una serie de reemplazos que se pasan cadenas en lugar de funciones.
Adam Leggett
34

Me doy cuenta de lo tarde que llego a esta fiesta, pero tengo una solución muy fácil que no requiere jQuery.

escaped = new Option(unescaped).innerHTML;

Editar: Esto no escapa a las comillas. El único caso en el que las comillas tendrían que escaparse es si el contenido se va a pegar en línea en un atributo dentro de una cadena HTML. Me resulta difícil imaginar un caso en el que hacerlo sea un buen diseño.

Edición 3: para la solución más rápida, verifique la respuesta anterior de Saram. Este es el más corto.

Adam Leggett
fuente
Esto no cambia las citas, al menos en este momento en Firefox 52.
getsetbro
1
Las comillas de escape solo son funcionalmente relevantes en los atributos. Dado que estamos escapando <y >, tampoco hay ningún beneficio en escapar de las citas, a menos que la intención del contenido generado sea ir a un atributo.
Adam Leggett
31

Aquí hay una función limpia y clara de JavaScript. Se escapará de texto como "unos pocos <muchos" a "unos pocos & lt; muchos".

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

Después de las últimas pruebas, puedo recomendar la solución javaScript (DOM) nativa compatible con el navegador más rápida y completamente compatible :

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

Si lo repite muchas veces, puede hacerlo con variables una vez preparadas:

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

Mira mi comparación de rendimiento final ( pregunta de pila ).

Saram
fuente
2
¿Es necesario usar dos nodos? ¿Qué tal solo uno?var p = document.createElement('p'); p.textContent = html; return p.innerHTML;
Dan Dascalescu
2
@DanDascalescu: según MDN , la textContentfunción solo es compatible con Chrome 1+, Firefox 2, IE9, Opera 9.64 y Safari 3 (estos dos últimos anotados "posiblemente antes"). Por lo tanto, rompería la afirmación de los OP "completamente compatibles con todos los navegadores".
zb226
p.innerText = html; return p.innerHTML
Bekim Bacaj
24

Prueba Underscore.string lib, funciona con jQuery.

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

salida:

'&lt;div&gt;Blah blah blah&lt;/div&gt;'
Nikita Koksharov
fuente
20
La biblioteca principal de subrayado ahora tiene una _.escape()función de utilidad.
codeape
15

He mejorado el ejemplo de bigote.js agregando el escapeHTML()método al objeto de cadena.

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

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

De esa manera es bastante fácil de usar. "Some <text>, more Text&Text".escapeHTML()

Jeena
fuente
Útil, pero también pasé __entityMapa la función de ámbito local. Y envuelto todo esto enif (typeof String.prototype.escapeHTML !== 'function'){...}
FlameStorm
15

escape() y unescape() están destinados a codificar / decodificar cadenas para URL, no HTML.

En realidad, utilizo el siguiente fragmento para hacer el truco que no requiere ningún marco:

var escapedHtml = html.replace(/&/g, '&amp;')
                      .replace(/>/g, '&gt;')
                      .replace(/</g, '&lt;')
                      .replace(/"/g, '&quot;')
                      .replace(/'/g, '&apos;');
NicolasBernier
fuente
Si vas a tener "s, entonces necesitas agregar al menos 'y `` a la refriega. Esos solo son realmente necesarios para datos de etiquetas de cadena dentro de elementos en html. Para los datos html en sí (etiquetas externas) solo se requieren los primeros 3.
Marius
10

Si tiene underscore.js, use _.escape(más eficiente que el método jQuery publicado anteriormente):

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

Si va por la ruta de expresiones regulares, hay un error en el ejemplo anterior de tghw.

<!-- 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
fuente
2
Creo que debería ser para (elemento var en findReplace) {escaped = escaped.replace (findReplace [item] [0], findReplace [item] [1]); }
Chris Stephens
5

Este es un buen ejemplo 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
fuente
44
¿Qué tipos de excepciones está suprimiendo allí?
Stefan Majewsky
3

Puedes hacerlo fácilmente con vanilla js.

Simplemente agregue un nodo de texto al documento. Será escapado por el navegador.

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

Sin variables globales, algo de optimización de memoria. Uso:

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

el resultado es:

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

2 métodos simples que NO requieren JQUERY ...

Puede codificar todos los caracteres en su cadena de esta manera:

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

O simplemente apuntar a los personajes principales que preocuparse &, saltos de línea, <, >, "y ', 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
fuente
2

Ejemplo de escape de JavaScript simple:

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
fuente
3
Se desaconsejan las respuestas de solo código porque no explican cómo resuelven el problema. Actualice su respuesta para explicar cómo mejora esto en las otras respuestas aceptadas y votadas que esta pregunta ya tiene. Además, esta pregunta tiene 9 años, sus esfuerzos serían más apreciados por los usuarios que tienen preguntas recientes sin respuesta. Por favor revise ¿Cómo escribo una buena respuesta ?
FluffyKitten
1
@FluffyKitten aquí es una publicación de blog extremadamente bien escrita sobre las ventajas y desventajas de dicha función que explica en detalle todo lo que le gustaría saber :) shebang.brandonmintern.com/…
db306
@ db306 La respuesta se marcó como de baja calidad porque la respuesta de solo código no cumple con las pautas de Desbordamiento de pila: consulte Cómo escribir una buena respuesta . Mi comentario fue agregado durante el proceso de revisión para explicar qué se necesita para mejorarlo, es decir, la respuesta debe actualizarse para explicar qué hace el código y cómo mejora las respuestas existentes. Los votos a favor provienen de otros revisores para respaldar esto. Agregar un enlace externo a los comentarios aún no cumple con las pautas de SO. En cambio, Andrew debe incluir la información relevante directamente en su respuesta.
FluffyKitten
Tenga en cuenta que brandonmintern DOT com expiró y ahora está estacionado. La nueva dirección de shebang es 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
fuente
0
function htmlDecode(t){
   if (t) return $('<div />').html(t).text();
}

Funciona de maravilla

d -_- b
fuente
el texto elimina las etiquetas html, pero $ ('<div />'). html (t) .html (); funciona
Bass Jobsen
0

Esta respuesta proporciona los métodos jQuery y JS normales, pero esto es más corto sin usar el DOM:

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

Cadena escapada: It%27s%20%3E%2020%25%20less%20complicated%20this%20way.

Si los espacios escapados te molestan, prueba:

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

Cadena escapada: It%27s %3E 20%25 less complicated this way.

Desafortunadamente, la escape()función fue obsoleta en JavaScript versión 1.5 . encodeURI()o encodeURIComponent()son alternativas, pero ignoran ', por lo que la última línea de código se convertiría en esto:

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

Todos los principales navegadores aún admiten el código corto, y dada la cantidad de sitios web antiguos, dudo que eso cambie pronto.

Cees Timmerman
fuente
Esto es para la codificación de URL. La pregunta era sobre el escape de HTML, que es muy diferente.
thelem
@thelem, no si las cadenas están incrustadas en matrices de JavaScript incrustadas en HTML, pero estoy de acuerdo en que se trataba de un simple escape de HTML para que pueda mostrarse inmediatamente como texto.
Cees Timmerman
0

ES6 one liner para la solución de mustache.js

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

Si está guardando esta información en una base de datos , es incorrecto escapar de HTML utilizando un script del lado del cliente , esto debe hacerse en el servidor . De lo contrario, es fácil eludir su protección XSS.

Para aclarar mi punto, aquí hay un ejemplo usando una de las respuestas:

Digamos que está utilizando la función escapeHtml para escapar del Html de un comentario en su blog y luego publicarlo en su servidor.

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

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

El usuario podría:

  • Edite los parámetros de solicitud POST y reemplace el comentario con código javascript.
  • Sobrescriba la función escapeHtml usando la consola del navegador.

Si el usuario pega este fragmento en la consola, pasará por alto la validación XSS:

function escapeHtml(string){
   return string
}
Kauê Gimenes
fuente
Estoy en desacuerdo. Para evitar esta protección XSS, tendría que usar un ataque XSS (inyectando un script que desactive el escape), que es lo que realmente está bloqueando. En ciertos casos, en realidad es más apropiado escapar en el cliente, por ejemplo, si los datos provienen de una API REST que tiene que devolver JSON estándar.
ItalyPaleAle
@Qualcuno Si realiza esta validación en el cliente y publica esta información en el servidor confiando en que se validó, el usuario podría simplemente editar la solicitud y el script se guardaría en la base de datos.
Kauê Gimenes
@Qualcuno Incluí algunos ejemplos para aclarar mi punto.
Kauê Gimenes
1
La pregunta era sobre las cadenas de escape recibidas del servidor para mostrarlas en el navegador. Lo que está diciendo es sobre escapar de las cadenas antes de enviarlas al servidor, lo cual es algo diferente (aunque tiene razón, allí, y se remonta a la regla anterior, nunca acepte ciegamente ninguna entrada del cliente )
ItalyPaleAle
@Qualcuno Esta es una pregunta popular en Stackoverflow, y creo que este es un punto importante que debe abordarse. Por eso respondí.
Kauê Gimenes
-2

Todas las soluciones son inútiles si no prevenir la re-escape, por ejemplo, la mayoría de las soluciones mantendrían escapar &a &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
fuente
44
Eso se llama doble escape y debe solucionarse asegurándose de que sus datos de entrada no se hayan escapado. ¿Qué pasaría si quisieras mostrar literalmente & lt; para el usuario? ¿O tal vez el texto se reutilizará en otro lugar y dependerá de que se haya producido el escape?
thelem