Cómo implementar la CSP y la depuración de Trusted Types en Herramientas para desarrolladores de Chrome

Kateryna Prokopenko
Kateryna Prokopenko
Alfonso Castaño
Alfonso Castaño

En esta entrada de blog, se describe la implementación de la compatibilidad de las Herramientas para desarrolladores para depurar problemas de la política de seguridad del contenido (CSP) con la ayuda de la pestaña Problemas que se presentó recientemente.

El trabajo de implementación se realizó en el transcurso de 2 pasantías: 1) Durante la primera, desarrollamos el marco de trabajo general de informes y diseñamos los mensajes de problemas para 3 problemas de incumplimiento de CSP. 2. Durante la segunda, agregamos problemas de Trusted Type junto con algunas funciones especializadas de Herramientas para desarrolladores para depurar Trusted Types.

¿Qué es una Política de Seguridad del Contenido?

La Política de Seguridad del Contenido (CSP) permite restringir ciertos comportamientos en un sitio web para aumentar la seguridad. Por ejemplo, la CSP se puede usar para inhabilitar secuencias de comandos intercaladas o eval, lo que reduce la superficie de ataque de los ataques de secuencias de comandos entre sitios (XSS). Para obtener una introducción detallada a CSP, consulta aquí.

Una CSP especialmente nueva es la política Trusted Types(TT), que permite un análisis dinámico que puede prevenir sistemáticamente una gran clase de ataques de inyección en sitios web. Para lograr esto, el TT permite que un sitio web polite su código JavaScript para permitir que solo se asignen ciertos tipos de elementos a receptores del DOM, como internalHTML.

Un sitio web puede activar una política de seguridad del contenido con la inclusión de un encabezado HTTP determinado. Por ejemplo, el encabezado content-security-policy: require-trusted-types-for 'script'; trusted-types default activa la política de VC para una página.

Cada política puede operar en uno de estos modos:

  • enforced mode, en el que cada incumplimiento de política es un error
  • modo de solo informes: Informa el mensaje de error como una advertencia, pero no provoca una falla en la página web.

Implementa problemas de la política de seguridad del contenido en la pestaña Problemas

El objetivo de este trabajo era mejorar la experiencia de depuración de los problemas de CSP. Cuando se consideran problemas nuevos, el equipo de Herramientas para desarrolladores sigue aproximadamente este proceso:

  1. Definición de historias de usuario. Identifica un conjunto de historias de usuario en el frontend de Herramientas para desarrolladores que explique cómo un desarrollador web tendría que investigar el problema.
  2. Implementación de frontend. En función de las historias de los usuarios, identifique qué información se requiere para investigar el problema en el frontend (por ejemplo, una solicitud relacionada, el nombre de una cookie, una línea en una secuencia de comandos o un archivo html, etc.).
  3. Detección de problemas. Identifica las partes del navegador donde se puede detectar el problema en Chrome y, luego, instrumenta el lugar para informar el problema, incluida la información relevante del paso (2).
  4. Guarda y muestra los problemas. Almacena los problemas en un lugar adecuado y haz que estén disponibles para Herramientas para desarrolladores una vez que se abra.
  5. Diseña el texto de los problemas. Crea un texto explicativo que ayude al desarrollador web a comprender y, lo que es más importante, solucionar el problema.

Paso 1: Definición de las historias de usuario para los problemas de CSP

Antes de comenzar nuestro trabajo de implementación, creamos un documento de diseño con historias de usuarios para comprender mejor lo que debíamos hacer. Por ejemplo, anotamos la siguiente historia de usuario:


Como desarrollador, que acaba de darse cuenta de que una parte de mi sitio web está bloqueada, quiero hacer lo siguiente: - ...averiguar si la CSP es una de las causas del bloqueo de iframes o imágenes en mi sitio web - ...aprender qué directiva de la CSP causa el bloqueo de un recurso determinado - ...sé cómo cambiar la CSP de mi sitio web para permitir que se muestren los recursos bloqueados o la ejecución de js bloqueados actualmente.


Para explorar esta historia de usuario, creamos algunas páginas web de ejemplo simples que mostraban las infracciones de la CSP que nos interesaban y exploramos las páginas de ejemplo para familiarizarnos con el proceso. Estas son algunas de las páginas web de ejemplo (abre la demostración con la pestaña Problemas abierta):

Con este proceso, descubrimos que la ubicación de origen era la información más importante para depurar problemas de CSP. También nos resultó útil encontrar rápidamente el iframe y la solicitud asociados en caso de que se bloquee un recurso. También nos pareció útil un vínculo directo al elemento HTML en el panel Elements de Herramientas para desarrolladores.

Paso 2: implementación del frontend

Convertimos esta información en el primer borrador de la información que queríamos poner a disposición para Herramientas para desarrolladores a través del protocolo de Herramientas para desarrolladores de Chrome (CDP):

A continuación, se incluye un extracto de third_party/blink/public/devtools_protocol/browser_protocol.pdl.

 type ContentSecurityPolicyIssueDetails extends object
   properties
     # The url not included in allowed sources.
     optional string blockedURL
     # Specific directive that is violated, causing the CSP issue.
     string violatedDirective
     boolean isReportOnly
     ContentSecurityPolicyViolationType contentSecurityPolicyViolationType
     optional AffectedFrame frameAncestor
     optional SourceCodeLocation sourceCodeLocation
     optional DOM.BackendNodeId violatingNodeId

La definición anterior básicamente codifica una estructura de datos JSON. Está escrito en un lenguaje simple llamado PDL (lenguaje de datos de protocolo). El PDL se usa para dos propósitos. Primero, usamos PDL para generar las definiciones de TypeScript en las que se basa el frontend de Herramientas para desarrolladores. Por ejemplo, la definición de PDL anterior genera la siguiente interfaz de TypeScript:

export interface ContentSecurityPolicyIssueDetails {
  /**
  * The url not included in allowed sources.
  */
  blockedURL?: string;
  /**
  * Specific directive that is violated, causing the CSP issue.
  */
  violatedDirective: string;
  isReportOnly: boolean;
  contentSecurityPolicyViolationType: ContentSecurityPolicyViolationType;
  frameAncestor?: AffectedFrame;
  sourceCodeLocation?: SourceCodeLocation;
  violatingNodeId?: DOM.BackendNodeId;
}

En segundo lugar, y quizás lo más importante, generamos una biblioteca de C++ a partir de la definición que administra la generación y el envío de estas estructuras de datos desde el backend de Chromium C++ al frontend de Herramientas para desarrolladores. Con esa biblioteca, se puede crear un objeto ContentSecurityPolicyIssueDetails con el siguiente fragmento de código de C++:

protocol::Audits::ContentSecurityPolicyIssueDetails::create()
  .setViolatedDirective(d->violated_directive)
  .setIsReportOnly(d->is_report_only)
  .setContentSecurityPolicyViolationType(BuildViolationType(
      d->content_security_policy_violation_type)))
  .build();

Una vez que determinamos qué información queríamos poner a disposición, necesitábamos explorar de dónde obtenemos esta información de Chromium.

Paso 3: detección de problemas

Para que la información esté disponible para el protocolo de Herramientas para desarrolladores de Chrome (CDP) en el formato descrito en la sección anterior, tuvimos que encontrar el lugar donde la información estaba realmente disponible en el backend. Por suerte, el código de la CSP ya tenía un cuello de botella que se usaba para el modo de solo informes, en el que podíamos conectarse a: ContentSecurityPolicy::ReportViolation informa los problemas a un extremo de informes (opcional) que se puede configurar en el encabezado HTTP de la CSP. La mayor parte de la información que queríamos informar ya estaba disponible, por lo que no fue necesario realizar grandes cambios en el backend para que nuestra instrumentación funcionara.

Paso 4: Guarda y muestra los problemas

Una pequeña complicación es el hecho de que también queríamos informar problemas que ocurrieron antes de que se abriera Herramientas para desarrolladores, de manera similar a cómo se manejan los mensajes de la consola. Esto significa que no informamos problemas de inmediato al frontend, sino que usamos un almacenamiento que contiene problemas independientemente de si Herramientas para desarrolladores está abierto o no. Una vez que se abre Herramientas para desarrolladores (o, en el caso de que se conecte cualquier otro cliente de CDP), todos los errores registrados previamente pueden volver a reproducirse desde el almacenamiento.

Esto concluyó el trabajo de backend y ahora necesitamos enfocarnos en cómo mostrar el problema en el frontend.

Paso 5: Diseña el texto de los problemas

Diseñar el texto de los problemas es un proceso que involucra a varios equipos además del nuestro, por ejemplo, a menudo nos basamos en información del equipo que implementa una función (en este caso, sería el equipo del CSP) y, por supuesto, el equipo de DevRel, que diseña cómo se supone que los desarrolladores web deben lidiar con un determinado tipo de problema. Por lo general, el texto del problema se perfecciona hasta finalizar.

Por lo general, el equipo de Herramientas para desarrolladores comenzará con un borrador de lo que imaginan:


## Header
Content Security Policy: include all sources of your resources in content security policy header to improve the functioning of your site

## General information
Even though some sources are included in the content security policy header, some resources accessed by your site like images, stylesheets or scripts originate from sources not included in content security policy directives.

Usage of content from not included sources is restricted to strengthen the security of your entire site.

## Specific information

### VIOLATED DIRECTIVES
`img-src 'self'`

### BLOCKED URLs
https://imgur.com/JuXCo1p.jpg

## Specific information
https://web.dev/strict-csp/

Después de la iteración, llegamos a lo siguiente:

ALT_TEXT_HERE

Como puedes ver, involucrar al equipo de funciones y a DevRel hace que la descripción sea mucho más clara y precisa.

Los problemas de la CSP en tu página también se pueden descubrir en la pestaña específicamente dedicada a los incumplimientos de la CSP.

Depura problemas de Trusted Types

Trabajar con TT a gran escala puede ser un desafío sin las herramientas para desarrolladores adecuadas.

Impresión mejorada desde la consola

Cuando trabajamos con objetos de confianza, nos gustaría mostrar al menos la misma cantidad de información que la del equivalente no confiable. Lamentablemente, en este momento, cuando se muestra un objeto de confianza, no se muestra información sobre el objeto unido.

Esto se debe a que el valor que se muestra en la consola se toma de llamar a .valueOf() en el objeto de forma predeterminada. Sin embargo, en el caso de Trusted Type, el valor que se muestra no es muy útil. En cambio, nos gustaría tener algo similar a lo que obtienes cuando llamas a .toString(). Para lograrlo, debemos modificar V8 y Blink para introducir un control especial para los objetos de tipo confiable.

Aunque, por razones históricas, este manejo personalizado se realizó en V8, este enfoque tiene importantes desventajas. Hay muchos objetos que requieren visualización personalizada, pero cuyo tipo es el mismo en el nivel de JS. Como V8 es puramente JS, no puede distinguir conceptos que corresponden a una API web como un tipo de confianza. Por ese motivo, V8 debe pedirle ayuda a su embedder (Blink) para distinguirlos.

Por lo tanto, mover esa parte del código a Blink o a cualquier incorporación suena como una elección lógica. Además del problema expuesto, existen muchos otros beneficios:

  • Cada incorporación puede tener su propia generación de descripciones
  • Es mucho más fácil generar la descripción con la API de Blink.
  • Blink tiene acceso a la definición original del objeto. Por lo tanto, si usamos .toString() para generar la descripción, no hay riesgo de que se redefine .toString().

Interrupción en caso de incumplimiento (en el modo de solo informes)

Actualmente, la única forma de depurar incumplimientos de TT es estableciendo puntos de interrupción en las excepciones de JS. Dado que las infracciones aplicadas de la TT activarán una excepción, esta función puede ser de alguna manera útil. Sin embargo, en situaciones del mundo real, necesita un control más detallado de las infracciones de TT. En particular, nos gustaría analizar solo las infracciones de VC (no otras excepciones), realizar también desgloses en el modo de solo informes y distinguir entre los diferentes tipos de infracciones de VC.

Las Herramientas para desarrolladores ya admiten una amplia variedad de puntos de interrupción, por lo que la arquitectura es bastante extensible. Para agregar un nuevo tipo de punto de interrupción, se requieren cambios en el backend (Blink), CDP y el frontend. Deberíamos introducir un nuevo comando de CDP, llamado setBreakOnTTViolation. El frontend utilizará este comando para indicarle al backend qué tipo de infracciones de TT debe interrumpir. El backend, en particular InspectorDOMDebuggerAgent, proporcionará un "sondeo", onTTViolation() al que se llamará cada vez que se produzca un incumplimiento de TT. Luego, InspectorDOMDebuggerAgent verificará si ese incumplimiento debe activar un punto de interrupción y, de ser así, enviará un mensaje al frontend para pausar la ejecución.

¿Qué se hace y cuáles son los próximos pasos?

Desde que se presentaron los problemas que se describen aquí, la pestaña Problemas experimentó algunos cambios:

En el futuro, planeamos usar la pestaña Problemas para mostrar más problemas, lo que permitirá descargar la consola del flujo ilegible de mensajes de error a largo plazo.

Descarga los canales de vista previa

Considera usar Chrome Canary, Dev o Beta como navegadores de desarrollo predeterminados. Estos canales de vista previa te brindan acceso a las funciones más recientes de Herramientas para desarrolladores, prueban API de plataforma web de vanguardia y detectan problemas en tu sitio antes que los usuarios.

Comunicarse con el equipo de Herramientas para desarrolladores de Chrome

Usa las siguientes opciones para hablar sobre las nuevas funciones y los cambios en la publicación, o cualquier otra cosa relacionada con Herramientas para desarrolladores.

  • Para enviarnos sugerencias o comentarios, accede a crbug.com.
  • Informa un problema en Herramientas para desarrolladores con Más opciones   Más > Ayuda > Informa problemas de Herramientas para desarrolladores en Herramientas para desarrolladores.
  • Twittea a @ChromeDevTools.
  • Deja comentarios en nuestros videos de YouTube de Herramientas para desarrolladores o en videos de YouTube de las Sugerencias de las Herramientas para desarrolladores.