Reduce la superficie de ataque de DOM XSS de tu aplicación.
¿Por qué debería importarte?
La secuencia de comandos entre sitios basada en DOM (DOM XSS) es una de las vulnerabilidades de seguridad web más comunes y es muy fácil introducirla en tu aplicación. Trust Types te proporciona las herramientas para escribir, revisar de seguridad y mantener aplicaciones libres de vulnerabilidades de XSS de DOM, ya que aseguran la seguridad de las funciones peligrosas de la API web. Trusted Types es compatible con Chrome 83 y un polyfill está disponible para otros navegadores. Consulta Compatibilidad con navegadores para obtener información actualizada sobre la compatibilidad en varios navegadores.
Información general
Durante muchos años, DOM XSS ha sido una de las vulnerabilidades de seguridad web más frecuentes y peligrosas.
Hay dos grupos distintos de secuencias de comandos entre sitios. Algunas vulnerabilidades XSS se producen por el código del servidor que crea de forma insegura el código HTML que forma el sitio web. Otros tienen una causa raíz en el cliente, en la que el código JavaScript llama a funciones peligrosas con contenido controlado por el usuario.
Para evitar XSS del servidor, no generes HTML mediante la concatenación de strings y usa bibliotecas seguras con plantillas de escape automático contextual. Usa una Política de Seguridad del Contenido basada en nonce para lograr una mitigación adicional contra los errores, a medida que inevitablemente ocurren.
Ahora un navegador también puede ayudar a evitar los XSS del cliente (también conocidos como basados en DOM) con Trust Types.
Introducción a la API
Trusted Types funciona bloqueando las siguientes funciones riesgosas de receptores. Es posible que ya reconozcas algunos de ellos, dado que los proveedores de navegadores y los frameworks web ya te impiden usar estas funciones por motivos de seguridad.
- Manipulación de secuencias de comandos:
<script src>
y configuración del contenido de texto de los elementos<script>
. Genera HTML a partir de una string:
innerHTML
,outerHTML
,insertAdjacentHTML
,<iframe> srcdoc
,document.write
,document.writeln
yDOMParser.parseFromString
Ejecución del contenido de complementos:
<embed src>
,<object data>
y<object codebase>
Compilación de código JavaScript en tiempo de ejecución:
eval
,setTimeout
,setInterval
,new Function()
Trusted Types requiere que proceses los datos antes de pasarlos a las funciones de receptor anteriores. Si solo usas una cadena, fallará, ya que el navegador no sabrá si los datos son confiables:
anElement.innerHTML = location.href;Cuando se habilita Trusted Types, el navegador muestra un TypeError e impide el uso de un receptor XSS de DOM con una cadena.
Para indicar que los datos se procesaron de forma segura, cree un objeto especial: un tipo de confianza.
anElement.innerHTML = aTrustedHTML;Con Trusted Types habilitado, el navegador acepta un objeto
TrustedHTML
para los receptores
que esperan fragmentos HTML. También hay objetos TrustedScript
y TrustedScriptURL
para otros receptores sensibles.
Los Trusted Types reducen en gran medida la superficie de ataque de DOM XSS de tu aplicación. Simplifica las revisiones de seguridad y te permite aplicar de manera forzosa los controles de seguridad basados en tipos que se realizan cuando se compila, analiza con lint o agrupa tu código en el tiempo de ejecución en el navegador.
Cómo usar Trusted Types
Prepárate para los informes de incumplimiento de la Política de Seguridad del Contenido
Puedes implementar un recopilador de informes (como el go-csp-collector de código abierto) o usar uno de los equivalentes comerciales.
También puedes depurar los incumplimientos en el navegador:
js
document.addEventListener('securitypolicyviolation',
console.error.bind(console));
Agrega un encabezado de CSP de solo informes
Agrega el siguiente encabezado de respuesta HTTP a los documentos que deseas migrar a Trusted Types.
text
Content-Security-Policy-Report-Only: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example
Ahora, todos los incumplimientos se informan a //my-csp-endpoint.example
, pero el sitio web sigue funcionando. En la siguiente sección, se explica cómo funciona //my-csp-endpoint.example
.
Identifica los incumplimientos de Trusted Types
A partir de ahora, cada vez que Trusted Types detecte un incumplimiento, se enviará un informe
a un report-uri
configurado. Por ejemplo, cuando tu aplicación pasa una string a innerHTML
, el navegador envía el siguiente informe:
{
"csp-report": {
"document-uri": "https://my.url.example",
"violated-directive": "require-trusted-types-for",
"disposition": "report",
"blocked-uri": "trusted-types-sink",
"line-number": 39,
"column-number": 12,
"source-file": "https://my.url.example/script.js",
"status-code": 0,
"script-sample": "Element innerHTML <img src=x"
}
}
Esto dice que, en https://my.url.example/script.js
, en la línea 39, se llamó a innerHTML
con la cadena que comienza con <img src=x
.
Esta información debería ayudarte a determinar qué partes del código pueden introducir DOM XSS y necesitas cambiar.
Corrija los incumplimientos
Hay un par de opciones para corregir un incumplimiento de tipo de confianza. Puedes quitar el código ofensivo, usar una biblioteca, crear una política de tipo de confianza o, como último recurso, crear una política predeterminada.
Vuelve a escribir el código ofensivo
Quizás ya no se necesite la funcionalidad que no cumple con los requisitos o se pueda reescribir de forma moderna sin usar las funciones propensas a errores.
el.innerHTML = '';
el.textContent = ''; const img = document.createElement('img'); img.src = 'xyz.jpg'; el.appendChild(img);
Cómo usar una biblioteca
Algunas bibliotecas ya generan Trusted Types que puedes pasar a las funciones del receptor. Por ejemplo, puedes usar DOMPurify para limpiar un fragmento HTML y quitar las cargas útiles de XSS.
import DOMPurify from 'dompurify';
el.innerHTML = DOMPurify.sanitize(html, {RETURN_TRUSTED_TYPE: true});
DOMPurify admite Trusted Types y muestra el código HTML depurado unido a un objeto TrustedHTML
para que el navegador no genere un incumplimiento.
Crea una política de tipo de confianza
En ocasiones, no es posible quitar la funcionalidad y no hay una biblioteca para limpiar el valor y crear un tipo de confianza para ti. En esos casos, crea un objeto de tipo de confianza por tu cuenta.
Para eso, primero crea una política. Las políticas son fábricas para Trusted Types que aplican ciertas reglas de seguridad a sus entradas:
if (window.trustedTypes && trustedTypes.createPolicy) { // Feature testing
const escapeHTMLPolicy = trustedTypes.createPolicy('myEscapePolicy', {
createHTML: string => string.replace(/\</g, '<')
});
}
Este código crea una política llamada myEscapePolicy
que puede producir objetos TrustedHTML
mediante su función createHTML()
. Las reglas definidas
se escaparán los caracteres HTML <
para evitar la creación de elementos HTML nuevos.
Utiliza la política de la siguiente manera:
const escaped = escapeHTMLPolicy.createHTML('<img src=x onerror=alert(1)>');
console.log(escaped instanceof TrustedHTML); // true
el.innerHTML = escaped; // '<img src=x onerror=alert(1)>'
Usa una política predeterminada
A veces, no puedes cambiar el código ofensivo. Por ejemplo, este es el caso si cargas una biblioteca de terceros desde una CDN. En ese caso, usa una política predeterminada:
if (window.trustedTypes && trustedTypes.createPolicy) { // Feature testing
trustedTypes.createPolicy('default', {
createHTML: (string, sink) => DOMPurify.sanitize(string, {RETURN_TRUSTED_TYPE: true})
});
}
La política con el nombre default
se usa cada vez que se usa una string en un receptor que solo acepta el tipo de confianza.
Cambiar para aplicar la Política de Seguridad del Contenido
Cuando tu aplicación ya no produce incumplimientos, puedes comenzar a aplicar Trusted Types:
Content-Security-Policy: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example
¡Listo! Sin importar lo compleja que sea tu aplicación web, lo único que puede introducir una vulnerabilidad de XSS de DOM es el código en una de tus políticas, y puedes bloquear eso aún más si limitas la creación de políticas.