- Para prevenir los ataques XSS, una de las principales vulnerabilidades de la web, Firefox se convierte en el primero en dar soporte a la Sanitizer API estandarizada
- Al usar el método setHTML() en lugar de innerHTML, el HTML no confiable se sanitiza automáticamente antes de insertarse en el DOM, eliminando scripts maliciosos
- Si la configuración predeterminada resulta demasiado estricta o insuficiente, los desarrolladores pueden controlar qué elementos y atributos se permiten mediante una configuración personalizada
- Esta función de Firefox, combinada con Trusted Types, eleva el nivel de seguridad de la web en general y permite prevenir XSS incluso sin contar con un equipo de seguridad dedicado
La vulnerabilidad XSS y la respuesta de Firefox
- El cross-site scripting (XSS) ocurre cuando un atacante inserta HTML o JavaScript arbitrario a través de contenido introducido por el usuario
- Con ello, el atacante puede vigilar la interacción del usuario o robar datos
- XSS ha sido clasificado durante casi 10 años como una de las 3 principales vulnerabilidades web (CWE-79)
- Firefox ha reforzado la defensa contra XSS desde 2009 liderando el estándar Content-Security-Policy (CSP)
- CSP limita los recursos que un sitio web puede cargar y ejecutar
- Sin embargo, requería cambios en la estructura de los sitios existentes y revisiones de seguridad continuas, por lo que su adopción masiva tenía limitaciones
El papel de Sanitizer API y setHTML()
- La Sanitizer API ofrece un método estandarizado para transformar HTML malicioso en una forma inocua
- En el código de ejemplo, el elemento
<img src="x" onclick="alert('XSS')"> se elimina y solo queda <h1>Hello my name is</h1>
- El método setHTML() ejecuta automáticamente el proceso de sanitización al insertar HTML, garantizando un comportamiento seguro por defecto
- Reemplazar la asignación con
innerHTML por setHTML() permite una fuerte defensa contra XSS
- Si la configuración predeterminada resulta demasiado estricta o flexible, los desarrolladores pueden definir los elementos y atributos HTML permitidos mediante una configuración personalizada
- Para experimentar, se puede utilizar la herramienta Sanitizer API playground
Combinación con Trusted Types
- La Trusted Types API proporciona una capa adicional de seguridad al controlar de forma centralizada el parseo y la inserción de HTML
- Al usar
setHTML(), se puede aplicar fácilmente una política de Trusted Types
- Una política estricta puede permitir solo
setHTML() y bloquear otros métodos de inserción riesgosos, ayudando a prevenir futuras regresiones de XSS
Mejora de seguridad en Firefox 148
- Firefox 148 admite tanto Sanitizer API como Trusted Types, lo que mejora considerablemente el nivel de seguridad por defecto
- Los desarrolladores pueden prevenir XSS con simples cambios de código sin necesidad de políticas de seguridad complejas ni de un equipo de seguridad aparte
- Se espera que la adopción de este estándar contribuya a extender un entorno web más seguro en todos los navegadores
Resumen
- Firefox 148 permite a los desarrolladores web bloquear fácilmente ataques XSS mediante el método setHTML() y la Sanitizer API
- Esta función complementa las limitaciones de CSP y marca un paso importante para establecer un método de inserción de HTML seguro por defecto como estándar web
- Su combinación con Trusted Types permite mantener la seguridad a largo plazo y evitar regresiones de XSS
- En consecuencia, Firefox está liderando la transición hacia un entorno web donde la seguridad es el valor predeterminado
2 comentarios
Oh, sí, definitivamente se necesitaba algo así. Estaría genial que todos los navegadores lo soportaran.
Opiniones de Hacker News
Este tipo de función siempre me da un poco de desconfianza
porque se mezclan métodos que manejan de forma segura entradas arbitrarias del usuario con otros que no, y solo por el nombre es difícil distinguirlos
Idealmente, desde el principio las funciones peligrosas deberían dejarlo claro en el nombre
Además, la idea misma de “sanitizar” HTML es ambigua, y es difícil saber si realmente es seguro
elimina elementos o atributos que puedan ejecutar scripts, y esta lógica corre dentro del motor del navegador, así que maneja esto con más precisión que un sanitizer basado en cadenas
Para más detalles, consulta la documentación de MDN sobre setHTML
elementNode.textContentes seguro incluso con entradas no confiables, yelementNode.innerHTMLno lo esel primero hace escape de todos los caracteres, y el segundo no hace escape de nada
También hay quienes opinan que la “sanitización de HTML” es un problema imposible de resolver en el fondo
véase este comentario para una discusión relacionada
una API así nunca debió pasar la etapa de propuesta
innerHTMLysetHTML, debería haberse diseñado eliminando por completoinnerHTMLy usandosetHTMLUnsafecuando se necesite el comportamiento anteriorinnerHTMLaunque entonces el sitio podría no funcionar en navegadores viejos
Content-Security-Policy: require-trusted-types-for 'script', puedes bloquear que se pasen cadenas normales a métodos sin sanitizerSi, como en el ejemplo, se pueden insertar etiquetas como
<h1>o<br>en el nombre de usuario, aunque se bloquee la ejecución de scripts sigue siendo posible la inyección arbitraria de marcadoTambién podrían alterar el CSS con una etiqueta
<style>, y por ejemplo cambiar el diseño de una página de perfil de PayPaluno se pregunta quién querría eso
puedes añadir una capa extra de defensa limitando otra vez con un sanitizer el HTML generado desde Markdown, permitiendo solo ciertas etiquetas
innerHTMLno, sinoinnerTextotextContentsetHTMLes un reemplazo parainnerHTMLsetHTML()es demasiado estricta o demasiado laxa, el desarrollador puede ofrecer una configuración personalizada para definir directamente qué elementos y atributos HTML se permitenvéase este hilo para una discusión relacionada
al final, en el backend todavía hay que sanitizar el nombre de usuario de la forma estándar, y al mostrarlo hay que aplicar escape de HTML
según RFC 2119, esto es un requisito de nivel “SHOULD”
Me alegra que aparezca esta función, pero parece que hará falta tiempo para que el soporte en navegadores se extienda lo suficiente
Puedes revisar el estado de compatibilidad en Can I use
mientras tanto puede sustituirse con un polyfill
El título era un poco sensacionalista
en realidad también se podría implementar la sanitización con una función que inspeccione la entrada antes de pasarla a
innerHTML, ¿no?pero este tipo de intentos termina sintiéndose como reinventar la rueda
además, en Firefox antiguos hacks.mozilla.org ni siquiera abre, y en Pale Moon o SeaMonkey MDN se ve roto
casi parece que un “cártel de navegadores” quisiera arruinar la web
además, es una afirmación que ni siquiera considera el problema de las diferencias entre parsers (parser differential)
Si se usa mal, la Sanitizer API puede convertirse en una footgun
sobre todo hay que tener cuidado al usar el modo “remove”
yo preferiría usar solo
setTexty no permitir en absoluto que el usuario agregue HTMLsetHTMLno ocurrirá XSSviendo lo común que es
innerHTML, parece difícil excluirlo por completoMe impresiona que todos los aspectos del acceso a red estén controlados correctamente, y que ahora la cadena de seguridad se haya movido de confiar en el código a confiar en la configuración del host
además, los valores por defecto están puestos de forma segura
Lo que yo de verdad quiero es un elemento
<sandbox>que permita ejecutar código peligroso de forma segurano corregir el código peligroso, sino poder correrlo en un entorno aislado
los
iframetienen la limitación de no fluir junto con el DOM, y en una era de IA y contenido dinámico creciente se necesita encapsulación componibleMe encanta el nombre
setHTMLUnsafelas funciones de seguridad fracasan cuando están diseñadas para que el desarrollador tenga que hacer opt-in
en cambio, funciona mejor hacer que “la ruta peligrosa se sienta peligrosa”
El nombre
set_html()es mucho más intuitivo queinner_htmllas APIs de JavaScript están realmente hechas un desastre y algún día deberían ordenarse
esta discusión se centra en la seguridad, pero cuando se publica una API nueva, el diseño en sí también debería ser limpio
las APIs del DOM desde hace mucho tiempo, y todavía hoy, dan la sensación de que “las hizo gente que nunca había diseñado una API”
Desarrolladores de los 90:
Desarrolladores de los 2020:
no aprendimos nada de los 90