Necesito mostrar los recursos externos cargados a través de solicitudes entre dominios y asegurarme de mostrar solo contenido " seguro ".
Podría usar String # stripScripts de Prototype para eliminar bloques de script. Pero los manipuladores como onclick
o onerror
todavía están allí.
¿Hay alguna biblioteca que pueda al menos
- bloques de secuencia de comandos de tira,
- matar a los controladores DOM,
- eliminar las etiquetas de la lista negra (por ejemplo:
embed
oobject
).
Entonces, ¿existen enlaces y ejemplos relacionados con JavaScript?
javascript
html
security
html-sanitizing
aemkei
fuente
fuente
Respuestas:
Actualización 2016: ahora hay un paquete de cierre de Google basado en el desinfectante Caja.
Tiene una API más limpia, se reescribió para tener en cuenta las API disponibles en los navegadores modernos e interactúa mejor con Closure Compiler.
Enchufe desvergonzado: consulte caja / plugin / html-sanitizer.js para obtener un desinfectante html del lado del cliente que ha sido revisado a fondo.
Está en la lista blanca, no en la lista negra, pero las listas blancas se pueden configurar según CajaWhitelists
Si desea eliminar todas las etiquetas, haga lo siguiente:
var tagBody = '(?:[^"\'>]|"[^"]*"|\'[^\']*\')*'; var tagOrComment = new RegExp( '<(?:' // Comment body. + '!--(?:(?:-*[^->])*--+|-?)' // Special "raw text" elements whose content should be elided. + '|script\\b' + tagBody + '>[\\s\\S]*?</script\\s*' + '|style\\b' + tagBody + '>[\\s\\S]*?</style\\s*' // Regular name + '|/?[a-z]' + tagBody + ')>', 'gi'); function removeTags(html) { var oldHtml; do { oldHtml = html; html = html.replace(tagOrComment, ''); } while (html !== oldHtml); return html.replace(/</g, '<'); }
La gente le dirá que puede crear un elemento y asignar
innerHTML
y luego obtener lainnerText
otextContent
, y luego escapar de las entidades en eso. No hagas eso. Es vulnerable a la inyección XSS, ya<img src=bogus onerror=alert(1337)>
que ejecutará elonerror
controlador incluso si el nodo nunca está adjunto al DOM.fuente
cssparser.js
, pero más importante, elhtml4
objeto). Además, contamina lawindow
propiedad global . ¿Existe una versión para la web de este código? Si no es así, ¿ve una mejor manera de producir y mantener uno que crear un proyecto separado para él?El desinfectante de HTML de Google Caja se puede hacer "listo para la web" insertándolo en un trabajador web . Cualquier variable global introducida por el desinfectante estará contenida dentro del trabajador, además el procesamiento tiene lugar en su propio hilo.
Para los navegadores que no son compatibles con Web Workers, podemos usar un iframe como un entorno separado para que funcione el desinfectante. Timothy Chien tiene un polyfill que hace exactamente esto, usando iframes para simular Web Workers, por lo que esa parte está hecha por nosotros.
El proyecto Caja tiene una página wiki sobre cómo utilizar Caja como un desinfectante independiente del lado del cliente :
ant
html-sanitizer-minified.js
ohtml-css-sanitizer-minified.js
en su páginahtml_sanitize(...)
El script del trabajador solo necesita seguir esas instrucciones:
importScripts('html-css-sanitizer-minified.js'); // or 'html-sanitizer-minified.js' var urlTransformer, nameIdClassTransformer; // customize if you need to filter URLs and/or ids/names/classes urlTransformer = nameIdClassTransformer = function(s) { return s; }; // when we receive some HTML self.onmessage = function(event) { // sanitize, then send the result back postMessage(html_sanitize(event.data, urlTransformer, nameIdClassTransformer)); };
(Se necesita un poco más de código para que funcione la biblioteca simworker, pero no es importante para esta discusión).
Demostración: https://dl.dropbox.com/u/291406/html-sanitize/demo.html
fuente
nameIdClassTransformer
se llama para cada nombre HTML, ID de elemento y lista de clases; regresarnull
eliminará el atributo. Al editar los archivos JSON en src / com / google / caja / lang / html , también puede personalizar qué elementos y atributos están incluidos en la lista blanca.nameIdClassTranformer
función anterior, por ejemplo, para rechazar todas las<script>
etiquetas y aceptar<b>
y<i>
etiquetas?Nunca confíes en el cliente. Si está escribiendo una aplicación de servidor, asuma que el cliente siempre enviará datos malintencionados e insalubres. Es una regla general que lo mantendrá fuera de problemas. Si puede, le recomendaría hacer toda la validación y el saneamiento en el código del servidor, que sabe (en un grado razonable) no se manipulará. ¿Quizás podría usar una aplicación web del lado del servidor como proxy para su código del lado del cliente, que obtiene de un tercero y realiza el saneamiento antes de enviarlo al cliente mismo?
[editar] Lo siento, entendí mal la pregunta. Sin embargo, sigo mi consejo. Sus usuarios probablemente estarán más seguros si desinfecta en el servidor antes de enviárselo.
fuente
Ahora que todos los navegadores principales admiten iframes de espacio aislado, hay una forma mucho más sencilla de que creo que puede ser segura. Me encantaría que esta respuesta pudiera ser revisada por personas más familiarizadas con este tipo de problema de seguridad.
NOTA: Este método definitivamente no funcionará en IE 9 y versiones anteriores. Consulte esta tabla para conocer las versiones del navegador que admiten la zona de pruebas. (Nota: la tabla parece indicar que no funcionará en Opera Mini, pero lo intenté y funcionó).
La idea es crear un iframe oculto con JavaScript desactivado, pegar su HTML que no es de confianza en él y dejar que lo analice. Luego, puede recorrer el árbol DOM y copiar las etiquetas y atributos que se consideran seguros.
Las listas blancas que se muestran aquí son solo ejemplos. Lo mejor para incluir en la lista blanca dependería de la aplicación. Si necesita una política más sofisticada que solo listas blancas de etiquetas y atributos, puede acomodarla con este método, aunque no con este código de ejemplo.
var tagWhitelist_ = { 'A': true, 'B': true, 'BODY': true, 'BR': true, 'DIV': true, 'EM': true, 'HR': true, 'I': true, 'IMG': true, 'P': true, 'SPAN': true, 'STRONG': true }; var attributeWhitelist_ = { 'href': true, 'src': true }; function sanitizeHtml(input) { var iframe = document.createElement('iframe'); if (iframe['sandbox'] === undefined) { alert('Your browser does not support sandboxed iframes. Please upgrade to a modern browser.'); return ''; } iframe['sandbox'] = 'allow-same-origin'; iframe.style.display = 'none'; document.body.appendChild(iframe); // necessary so the iframe contains a document iframe.contentDocument.body.innerHTML = input; function makeSanitizedCopy(node) { if (node.nodeType == Node.TEXT_NODE) { var newNode = node.cloneNode(true); } else if (node.nodeType == Node.ELEMENT_NODE && tagWhitelist_[node.tagName]) { newNode = iframe.contentDocument.createElement(node.tagName); for (var i = 0; i < node.attributes.length; i++) { var attr = node.attributes[i]; if (attributeWhitelist_[attr.name]) { newNode.setAttribute(attr.name, attr.value); } } for (i = 0; i < node.childNodes.length; i++) { var subCopy = makeSanitizedCopy(node.childNodes[i]); newNode.appendChild(subCopy, false); } } else { newNode = document.createDocumentFragment(); } return newNode; }; var resultElement = makeSanitizedCopy(iframe.contentDocument.body); document.body.removeChild(iframe); return resultElement.innerHTML; };
Puedes probarlo aquí .
Tenga en cuenta que estoy rechazando los atributos y etiquetas de estilo en este ejemplo. Si los permitiste, probablemente querrás analizar el CSS y asegurarte de que sea seguro para tus propósitos.
Probé esto en varios navegadores modernos (Chrome 40, Firefox 36 Beta, IE 11, Chrome para Android) y en uno antiguo (IE 8) para asegurarme de que funcionara antes de ejecutar cualquier script. Me interesaría saber si hay navegadores que tengan problemas con él, o casos extremos que estoy pasando por alto.
fuente
iframe.contentDocument.body.innerHTML = input
, se ejecutarán las etiquetas de script que contenga.sandbox
atributo.No puede anticipar todos los posibles tipos extraños de marcado mal formado con el que algún navegador en algún lugar podría tropezar para escapar de la lista negra, así que no lo haga. Hay muchas más estructuras que podría necesitar eliminar además de script / incrustación / objeto y controladores.
En su lugar, intente analizar el HTML en elementos y atributos en una jerarquía, luego ejecute todos los nombres de elementos y atributos en una lista blanca lo más mínima posible. También verifique cualquier atributo de URL que deje pasar en una lista blanca (recuerde que hay protocolos más peligrosos que solo javascript :).
Si la entrada es XHTML bien formado, la primera parte de lo anterior es mucho más fácil.
Como siempre con el saneamiento de HTML, si puede encontrar alguna otra forma de evitar hacerlo, hágalo en su lugar. Hay muchos, muchos agujeros potenciales. Si los principales servicios de correo web siguen encontrando vulnerabilidades después de tantos años, ¿qué le hace pensar que puede hacerlo mejor?
fuente
Entonces, es 2016, y creo que muchos de nosotros estamos usando
npm
módulos en nuestro código ahora.sanitize-html
parece ser la opción principal en npm, aunque hay otras .Otras respuestas a esta pregunta brindan una excelente información sobre cómo desarrollar la suya propia, pero este es un problema lo suficientemente complicado como para que las soluciones comunitarias bien probadas sean probablemente la mejor respuesta.
Ejecute esto en la línea de comando para instalar:
npm install --save sanitize-html
ES5:
var sanitizeHtml = require('sanitize-html'); // ... var sanitized = sanitizeHtml(htmlInput);
ES6:
import sanitizeHtml from 'sanitize-html'; // ... let sanitized = sanitizeHtml(htmlInput);
fuente
[Descargo de responsabilidad: soy uno de los autores]
Escribimos una biblioteca de código abierto "solo web" (es decir, "requiere un navegador") para esto, https://github.com/jitbit/HtmlSanitizer que elimina todos
tags/attributes/styles
excepto los "incluidos en la lista blanca".Uso:
var input = HtmlSanitizer.SanitizeHtml("<script> Alert('xss!'); </scr"+"ipt>");
PS Funciona mucho más rápido que una solución de "JavaScript puro", ya que utiliza el navegador para analizar y manipular DOM. Si está interesado en una solución de "JS puro", pruebe https://github.com/punkave/sanitize-html (no afiliado)
fuente
La biblioteca de Google Caja sugerida anteriormente era demasiado compleja para configurar e incluir en mi proyecto para una aplicación web (por lo tanto, ejecutándose en el navegador). Lo que recurrí en su lugar, dado que ya usamos el componente CKEditor, es usar su función incorporada de desinfección y lista blanca de HTML, que es mucho más fácil de configurar. Entonces, puede cargar una instancia de CKEditor en un iframe oculto y hacer algo como:
CKEDITOR.instances['myCKEInstance'].dataProcessor.toHtml(myHTMLstring)
Ahora, por supuesto, si no está utilizando CKEditor en su proyecto, esto puede ser un poco exagerado, ya que el componente en sí tiene alrededor de medio megabyte (minimizado), pero si tiene las fuentes, tal vez pueda aislar el código haciendo la lista blanca (
CKEDITOR.htmlParser
?) y hacerla mucho más corta.http://docs.ckeditor.com/#!/api
http://docs.ckeditor.com/#!/api/CKEDITOR.htmlDataProcessor
fuente
Recomiendo eliminar los marcos de tu vida, te facilitaría mucho las cosas a largo plazo.
cloneNode: La clonación de un nodo copias de todos sus atributos y sus valores, pero no NO copiar los detectores de eventos .
https://developer.mozilla.org/en/DOM/Node.cloneNode
Lo siguiente no está probado, aunque he estado usando treewalkers desde hace algún tiempo y son una de las partes más infravaloradas de JavaScript. Aquí hay una lista de los tipos de nodos que puede rastrear, normalmente yo uso SHOW_ELEMENT o SHOW_TEXT .
http://www.w3.org/TR/DOM-Level-2-Traversal-Range/traversal.html#Traversal-NodeFilter
function xhtml_cleaner(id) { var e = document.getElementById(id); var f = document.createDocumentFragment(); f.appendChild(e.cloneNode(true)); var walker = document.createTreeWalker(f,NodeFilter.SHOW_ELEMENT,null,false); while (walker.nextNode()) { var c = walker.currentNode; if (c.hasAttribute('contentEditable')) {c.removeAttribute('contentEditable');} if (c.hasAttribute('style')) {c.removeAttribute('style');} if (c.nodeName.toLowerCase()=='script') {element_del(c);} } alert(new XMLSerializer().serializeToString(f)); return f; } function element_del(element_id) { if (document.getElementById(element_id)) { document.getElementById(element_id).parentNode.removeChild(document.getElementById(element_id)); } else if (element_id) { element_id.parentNode.removeChild(element_id); } else { alert('Error: the object or element \'' + element_id + '\' was not found and therefore could not be deleted.'); } }
fuente