Pregunta

¿Alguien conoce 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 en este momento no sé lo suficiente sobre el marco para lograrlo.

¿Fue útil?

Solución

Dado que está utilizando jQuery , puede configurar el elemento text propiedad:

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

Otros consejos

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];
  });
}
$('<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

Si está escapándose de HTML, solo creo que tres 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 deba hacer cosas como " a &quot;. Si la lista se volviera lo suficientemente grande, 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 URL, no para HTML.

Escribí una pequeña función que hace esto.solo se escapa ", &, < y > (pero normalmente eso es todo lo que necesitas de todos modos).Es un poco más elegante que las soluciones propuestas anteriormente porque solo utiliza uno .replace() para hacer toda la conversión.(EDITAR 2: Complejidad reducida del código que hace que la función sea aún más pequeña y ordenada. Si tiene curiosidad sobre el código original, consulte 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

Editar en respuesta a mklementoEl comentario de.

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 de la expresión regular (es decir,dentro de /[...]/g) y como entrada en el chr objeto.(EDITAR 2: Esta función también se acortó 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 el apóstrofe (la entidad simbólica &apos; podría haberse utilizado en su lugar: está definido en XML, pero originalmente no estaba incluido en la especificación HTML y, por lo tanto, es posible que no sea 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 el uso de entidades decimales es más compatible que el uso hexadecimal, pero parece que ahora no puedo encontrar la fuente para eso.(Y no puede haber muchos navegadores que no admitan entidades hexadecimales).

Nota: Añadiendo / y ' a la lista de caracteres de escape no es tan útil, ya que no tienen ningún significado especial en HTML y no necesidad para escapar.

Original escapeHtml Función

EDITAR 2: La función original usaba una variable (chr) para almacenar el objeto necesario para el .replace() llamar de vuelta.Esta variable también necesitaba una función anónima adicional para definir su alcance, lo que hacía que la función (innecesariamente) fuera un poco más grande y 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 es así, no dudes en agregar información y enlaces al respecto aquí.

Suficientemente fácil de usar subrayado:

_.escape(string) 

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

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 2: si el rendimiento es crucial, la solución de mayor rendimiento (en aproximadamente un 50%) sigue siendo una serie de reemplazos de expresiones regulares. Los navegadores modernos detectarán que las expresiones regulares no contienen operadores, solo una cadena, y las colapsarán en una sola operación.

Aquí hay una función JavaScript limpia y clara. Se escapará de texto como & Quot; algunos & Lt; muchos " en " algunos & amp; 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;');
}

Después de las últimas pruebas, puedo recomendar la solución más rápida y completamente de navegador cruzado javaScript nativo (DOM) 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 rendimiento final comparación ( pregunta de pila ).

Pruebe Underscore.string lib, funciona con jQuery.

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

salida:

'&lt;div&gt;Blah blah blah&lt;/div&gt;'

He mejorado el ejemplo de bigote.js agregando el método escapeHTML() 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()

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

En realidad, uso 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;');

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

Si vas 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]]);
}

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

Puedes hacerlo fácilmente con vanilla js.

Simplemente agregue un nodo de texto al documento. El navegador lo escapará.

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

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

Puede codificar todos los caracteres en tu cadena así:

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

O solo apunta a los personajes principales preocuparse de &, 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>

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;"
function htmlDecode(t){
   if (t) return $('<div />').html(t).text();
}

funciona como un encanto

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 función escape() era en desuso 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.

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, omitirá la validación XSS:

function escapeHtml(string){
   return string
}

Todas las soluciones son inútiles si no evitas volver a escapar, p. la mayoría de las soluciones seguirían escapando & 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] + ";";
        }
    ) : "";
};
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top