Implémenter le débogage de CSP et des Trusted Types dans les outils pour les développeurs Chrome

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

Cet article de blog traite de l'implémentation de la compatibilité des outils de développement pour le débogage des problèmes liés à la Content Security Policy (CSP) à l'aide de l'onglet Problèmes récemment introduit.

L'implémentation a été réalisée au cours de deux stages : 1. Lors de la première, nous avons créé le framework de reporting général et conçu les messages d'erreur pour trois problèmes de non-respect de la CSP. 2. Lors de la deuxième, nous avons ajouté les problèmes liés aux types de confiance, ainsi que des fonctionnalités DevTools spécialisées pour le débogage des types de confiance.

Qu'est-ce qu'une Content Security Policy ?

La Content Security Policy (CSP) permet de limiter certains comportements sur un site Web afin d'en renforcer la sécurité. Par exemple, la CSP peut être utilisée pour interdire les scripts intégrés ou eval, ce qui réduit la surface d'attaque pour les attaques par script intersites (XSS). Pour une présentation détaillée de la CSP, cliquez ici.

La règle Trusted Types(TT) est une CSP particulièrement récente. Elle permet une analyse dynamique qui peut empêcher systématiquement une grande partie des attaques par injection sur les sites Web. Pour ce faire, les TT aident un site Web à contrôler son code JavaScript afin de n'autoriser que certains types d'éléments à être attribués à des récepteurs DOM tels que innerHTML.

Un site Web peut activer une Content Security Policy en incluant un en-tête HTTP particulier. Par exemple, l'en-tête content-security-policy: require-trusted-types-for 'script'; trusted-types default active la règle TT pour une page.

Chaque stratégie peut fonctionner dans l'un des modes suivants :

  • Mode forcé : chaque non-respect des règles est une erreur.
  • Mode rapport uniquement : signale le message d'erreur sous forme d'avertissement, mais ne provoque pas d'échec sur la page Web.

Implémenter les problèmes de Content Security Policy dans l'onglet Problèmes

L'objectif de ce travail était d'améliorer l'expérience de débogage des problèmes de CSP. Lorsqu'elle examine de nouveaux problèmes, l'équipe DevTools suit à peu près ce processus :

  1. Définir des user stories Identifiez un ensemble d'histoires de l'utilisateur dans l'interface des outils de développement qui couvre la manière dont un développeur Web devrait examiner le problème.
  2. Implémentation de l'interface. En fonction des user stories, identifiez les informations nécessaires pour examiner le problème dans l'interface (par exemple, une requête associée, le nom d'un cookie, une ligne dans un script ou un fichier HTML, etc.).
  3. Détection des problèmes. Identifiez les endroits du navigateur où le problème peut être détecté dans Chrome et instrumentez l'endroit pour signaler un problème, y compris les informations pertinentes de l'étape (2).
  4. Enregistrez et affichez les problèmes. Stocker les problèmes dans un emplacement approprié et les mettre à la disposition des outils de développement une fois qu'ils sont ouverts
  5. Concevoir le texte des problèmes. Rédige un texte explicatif qui aide le développeur Web à comprendre et, plus important encore, à résoudre le problème.

Étape 1 : Définir des user stories pour les problèmes de CSP

Avant de commencer l'implémentation, nous avons créé un document de conception avec des user stories pour mieux comprendre ce que nous devions faire. Par exemple, nous avons écrit la user story suivante :


En tant que développeur, je viens de me rendre compte que certaines parties de mon site Web sont bloquées. Je souhaite : - ...savoir si la CSP est la cause du blocage des iFrames / images sur mon site Web - ...savoir quelle directive CSP est à l'origine du blocage d'une certaine ressource - ...savoir comment modifier la CSP de mon site Web pour autoriser l'affichage des ressources actuellement bloquées / l'exécution du code JS actuellement bloqué.


Pour explorer cette user story, nous avons créé quelques exemples de pages Web simples qui présentaient les violations de CSP qui nous intéressaient, et nous avons exploré ces exemples de pages pour nous familiariser avec le processus. Voici quelques exemples de pages Web (ouvrez la démonstration avec l'onglet Problèmes ouvert) :

Grâce à ce processus, nous avons appris que l'emplacement source était l'information la plus importante pour déboguer les problèmes de CSP. Nous avons également trouvé utile de pouvoir trouver rapidement l'iframe et la requête associées lorsqu'une ressource est bloquée, et de disposer d'un lien direct vers l'élément HTML dans le panneau Éléments des outils de développement.

Étape 2 : Implémentation du frontend

Nous avons transformé ces informations en un premier brouillon des informations que nous voulions mettre à la disposition de DevTools via le protocole Chrome DevTools (CDP) :

Voici un extrait 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 définition ci-dessus encode essentiellement une structure de données JSON. Il est écrit dans un langage simple appelé PDL (Protocol Data Language). Le PDL est utilisé à deux fins. Tout d'abord, nous utilisons le PDL pour générer les définitions TypeScript sur lesquelles repose l'interface des outils de développement. Par exemple, la définition PDL ci-dessus génère l'interface TypeScript suivante :

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

Deuxièmement, et c'est probablement le plus important, nous générons une bibliothèque C++ à partir de la définition qui gère la génération et l'envoi de ces structures de données du backend Chromium C++ vers l'interface des outils de développement. Cette bibliothèque permet de créer un objet ContentSecurityPolicyIssueDetails à l'aide de l'extrait de code C++ suivant :

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

Une fois que nous avons déterminé les informations que nous voulions rendre disponibles, nous avons dû chercher où les obtenir dans Chromium.

Étape 3 : Détection des problèmes

Pour que les informations soient disponibles pour le protocole Chrome DevTools (CDP) au format décrit dans la dernière section, nous devions trouver l'endroit où les informations étaient réellement disponibles dans le backend. Heureusement, le code CSP comportait déjà un goulot d'étranglement utilisé pour le mode "Rapports uniquement", auquel nous pouvions nous connecter : ContentSecurityPolicy::ReportViolation signale les problèmes à un point de terminaison de rapport (facultatif) qui peut être configuré dans l'en-tête HTTP CSP. La plupart des informations que nous voulions signaler étaient déjà disponibles. Nous n'avons donc pas eu besoin d'apporter de modifications majeures au backend pour que notre instrumentation fonctionne.

Étape 4 : Enregistrer et afficher les problèmes

Une petite complication réside dans le fait que nous voulions également signaler les problèmes survenus avant l'ouverture des outils de développement, de la même manière que les messages de la console sont gérés. Cela signifie que nous ne signalons pas les problèmes directement au frontend, mais que nous utilisons un espace de stockage qui est alimenté par les problèmes, que les outils de développement soient ouverts ou non. Une fois les outils de développement ouverts (ou tout autre client CDP associé), tous les problèmes précédemment enregistrés peuvent être rejoués à partir de l'espace de stockage.

Nous avions terminé le travail sur le backend et devions maintenant nous concentrer sur la façon de signaler le problème dans le frontend.

Étape 5 : Concevoir le texte des problèmes

La conception du texte des problèmes est un processus qui implique plusieurs équipes en plus de la nôtre. Par exemple, nous nous appuyons souvent sur les insights de l'équipe qui implémente une fonctionnalité (dans ce cas, l'équipe CSP) et, bien sûr, de l'équipe DevRel, qui conçoit la manière dont les développeurs Web sont censés gérer un certain type de problème. Le texte du problème est généralement affiné jusqu'à ce qu'il soit terminé.

En général, l'équipe DevTools commence par un brouillon de ce qu'elle imagine :


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

Après itération, nous sommes arrivés à :

ALT_TEXT_HERE

Comme vous pouvez le voir, l'implication de l'équipe chargée de la fonctionnalité et de l'équipe DevRel rend la description beaucoup plus claire et précise.

Les problèmes de CSP sur votre page peuvent également être détectés dans l'onglet spécifiquement dédié aux cas de non-respect de la CSP.

Déboguer les problèmes liés aux types de confiance

Il peut être difficile de travailler avec TT à grande échelle sans les bons outils pour les développeurs.

Amélioration de l'impression de la console

Lorsque nous travaillons avec des objets de confiance, nous souhaitons afficher au moins la même quantité d'informations que pour l'équivalent non fiable. Malheureusement, lorsqu'un objet de confiance est affiché, aucune information sur l'objet encapsulé n'est affichée.

En effet, la valeur affichée dans la console est extraite en appelant .valueOf() sur l'objet par défaut. Toutefois, dans le cas d'un type de confiance, la valeur renvoyée n'est pas très utile. Nous souhaitons plutôt obtenir un résultat semblable à celui que vous obtenez en appelant .toString(). Pour ce faire, nous devons modifier V8 et Blink afin d'introduire un traitement spécial pour les objets de type de confiance.

Bien que, pour des raisons historiques, ce traitement personnalisé ait été effectué dans V8, une telle approche présente des inconvénients importants. De nombreux objets nécessitent un affichage personnalisé, mais leur type est le même au niveau JS. Comme V8 est du JS pur, il ne peut pas distinguer les concepts qui correspondent à une API Web, comme un type de confiance. C'est pourquoi V8 doit demander de l'aide à son intégrateur (Blink) pour les distinguer.

Par conséquent, déplacer cette partie du code vers Blink ou tout autre intégrateur semble être un choix logique. En plus de résoudre le problème exposé, cela présente de nombreux autres avantages :

  • Chaque outil d'intégration peut avoir sa propre génération de description
  • Il est beaucoup plus facile de générer la description via l'API Blink.
  • Blink a accès à la définition d'origine de l'objet. Ainsi, si nous utilisons .toString() pour générer la description, il n'y a aucun risque que .toString() soit redéfini.

Interruption en cas de non-respect (en mode rapport uniquement)

Actuellement, la seule façon de déboguer les cas de non-respect des types de confiance consiste à définir des points d'arrêt sur les exceptions JS. Étant donné que les violations de types de confiance appliqués déclenchent une exception, cette fonctionnalité peut être utile. Toutefois, dans des scénarios réels, vous avez besoin d'un contrôle plus précis des violations de TT. En particulier, nous aimerions interrompre l'exécution uniquement en cas de non-respect des types de confiance (et non pour d'autres exceptions), interrompre l'exécution également en mode rapport uniquement et distinguer les différents types de non-respect des types de confiance.

Les outils de développement sont déjà compatibles avec un grand nombre de points d'arrêt. L'architecture est donc assez extensible. L'ajout d'un nouveau type de point d'arrêt nécessite des modifications dans le backend (Blink), le CDP et l'interface. Nous devrions introduire une nouvelle commande CDP, appelons-la setBreakOnTTViolation. Cette commande sera utilisée par l'interface pour indiquer au backend sur quel type de violation de TT il doit s'arrêter. Le backend, en particulier InspectorDOMDebuggerAgent, fournira une "sonde", onTTViolation(), qui sera appelée chaque fois qu'une violation de TT se produit. Ensuite, InspectorDOMDebuggerAgent vérifie si cette violation doit déclencher un point d'arrêt. Si c'est le cas, il envoie un message au frontend pour suspendre l'exécution.

Qu'est-ce qui a été fait et que reste-t-il à faire ?

Depuis l'introduction des problèmes décrits ici, l'onglet Problèmes a subi quelques modifications :

À l'avenir, nous prévoyons d'utiliser l'onglet Problèmes pour afficher davantage de problèmes, ce qui permettra à terme de décharger la console du flux de messages d'erreur illisibles.

Télécharger les canaux de prévisualisation

Envisagez d'utiliser Chrome Canary, Dev ou Beta comme navigateur de développement par défaut. Ces canaux de preview vous donnent accès aux dernières fonctionnalités des outils de développement, vous permettent de tester des API de plate-forme Web de pointe et vous aident à détecter les problèmes sur votre site avant vos utilisateurs.

Contacter l'équipe des Outils pour les développeurs Chrome

Utilisez les options suivantes pour discuter des nouvelles fonctionnalités, des mises à jour ou de tout autre sujet lié aux outils de développement.