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 concerne l'implémentation de la prise en charge des outils de développement pour déboguer les problèmes liés à Content Security Policy (CSP) à l'aide de l'onglet Issues (Problèmes) introduit récemment.

Le travail de mise en œuvre a été effectué au cours de deux stages: 1. Dans le premier cas, nous avons élaboré le cadre général de reporting et conçu les messages concernant trois problèmes de non-respect de CSP. 2. Dans la seconde, nous avons ajouté les problèmes liés aux Trusted Types, ainsi que des fonctionnalités spécialisées des outils de développement pour le débogage des Trusted Types.

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

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

La règle TT(Trusted Types) est un fournisseur de services de communication particulièrement nouveau. Elle permet d'effectuer une analyse dynamique capable d'empêcher systématiquement un grand nombre d'attaques par injection sur les sites Web. Pour ce faire, TT permet à un site Web de contrôler son code JavaScript de sorte que seuls certains types d'éléments puissent être attribués aux récepteurs DOM, tels que innerHTML.

Un site Web peut activer une politique de sécurité du contenu 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 règle peut fonctionner dans l'un des modes suivants:

  • mode application forcée : dans lequel chaque cas de non-respect des règles est une erreur.
  • mode rapport uniquement : ce mode signale le message d'erreur en tant qu'avertissement, mais ne provoque pas d'échec sur la page Web.

Implémentation des problèmes liés à Content Security Policy dans l'onglet Issues (Problèmes)

L'objectif de ce travail était d'améliorer l'expérience de débogage pour les problèmes liés à CSP. Lorsqu'elle étudie de nouveaux problèmes, l'équipe DevTools suit à peu près la procédure suivante:

  1. Définition des histoires d'utilisateurs. Dans l'interface des outils de développement, identifiez un ensemble d'histoires d'utilisateurs décrivant la façon dont un développeur Web devrait enquêter sur le problème.
  2. Implémentation en front-end : En vous basant sur les histoires des utilisateurs, identifiez les informations requises pour enquêter sur le problème dans l'interface (par exemple, une demande associée, le nom d'un cookie, une ligne de script ou de fichier html, etc.).
  3. Détection des problèmes : Identifiez les emplacements du navigateur où le problème peut être détecté dans Chrome et instrumentez-le pour signaler un problème, en incluant les informations pertinentes de l'étape 2.
  4. Enregistrez et affichez les problèmes. Conservez les problèmes à l'emplacement approprié et mettez-les à la disposition des outils de développement une fois qu'ils sont ouverts.
  5. Texte concernant la conception de problèmes. Imaginez un texte explicatif qui aide le développeur Web à comprendre et, plus important encore, à résoudre le problème.

Étape 1: Définir des histoires d'utilisateurs pour les problèmes liés à CSP

Avant de commencer notre implémentation, nous avons créé un document de conception contenant des histoires d'utilisateurs afin de mieux comprendre ce que nous devions faire. Par exemple, nous avons écrit l’histoire d’utilisateur suivante:


En tant que développeur, qui vient de réaliser qu'une partie de mon site Web est bloquée, je souhaite : - ... déterminer si CSP entraîne le blocage des images / iFrames sur mon site Web. - ...découvrir quelle directive CSP entraîne le blocage d'une ressource donnée - ...savoir comment modifier la CSP de mon site Web pour autoriser l'affichage des ressources actuellement bloquées / l'exécution du code JavaScript actuellement bloqué.


Pour explorer cette histoire d'utilisateur, nous avons créé quelques exemples de pages Web simples qui présentent les violations de CSP qui nous intéressaient, et nous avons exploré ces pages d'exemple pour nous familiariser avec le processus. Voici quelques exemples de pages Web (ouvrez la démonstration en ouvrant l'onglet Issues [Problèmes]):

Grâce à ce processus, nous avons découvert que l'emplacement source était l'information la plus importante pour le débogage des problèmes liés à CSP. Nous avons également trouvé utile de trouver rapidement l'iFrame et la requête associés au cas où une ressource serait bloquée, et qu'un lien direct vers l'élément HTML dans le panneau Elements des outils de développement pouvait également être utile.

Étape 2: Implémentation de l'interface

Nous avons transformé ces insights en la première ébauche des informations que nous voulions mettre à la disposition des outils de développement via le protocole CDP (Chrome DevTools Protocol):

Vous trouverez ci-dessous un extrait du fichier 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). PDL est utilisé pour deux raisons. Tout d'abord, nous utilisons PDL pour générer les définitions TypeScript sur lesquelles l'interface des outils de développement s'appuie. 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 probablement et surtout, nous générons à partir de la définition une bibliothèque C++ qui gère la génération et l'envoi de ces structures de données depuis le backend Chromium C++ vers l'interface DevTools. À l'aide de cette bibliothèque, vous pouvez 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 souhaitions rendre accessibles, nous avons dû déterminer où les trouver dans Chromium.

Étape 3: détection des problèmes

Pour mettre les informations à la disposition du Chrome DevTools Protocol (CDP), au format décrit dans la section précédente, nous avons dû trouver l'emplacement où ces informations étaient réellement disponibles dans le backend. Heureusement, le code CSP disposait déjà d'un goulot d'étranglement utilisé en mode rapport uniquement, auquel nous pouvions nous connecter: ContentSecurityPolicy::ReportViolation signale les problèmes à un point de terminaison de signalement (facultatif) qui peut être configuré dans l'en-tête HTTP de CSP. La plupart des informations que nous voulions signaler étaient déjà disponibles. Par conséquent, aucun changement majeur n'a été nécessaire en arrière-plan pour que notre instrumentation fonctionne.

Étape 4: Enregistrez et affichez les problèmes

Petit problème : nous voulions également signaler les problèmes qui se sont produits avant l'ouverture des outils de développement, de la même manière que les messages de la console. Cela signifie que nous ne signalons pas immédiatement les problèmes au frontend, mais que nous utilisons un espace de stockage qui contient les problèmes, que les outils de développement soient ouverts ou non. Une fois les outils de développement ouverts (ou, d'ailleurs, tout autre client CDP associé), tous les problèmes précédemment enregistrés peuvent être relus depuis l'espace de stockage.

Le travail en arrière-plan est maintenant terminé. Nous devions maintenant nous concentrer sur la façon de détecter le problème dans l'interface.

Étape 5: rédiger le texte sur les questions

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 informations 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é.

Habituellement, l'équipe DevTools commence par une ébauche 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 l'itération, nous sommes arrivés à:

ALT_TEXT_HERE

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

Les problèmes liés à CSP sur votre page sont également disponibles dans l'onglet dédié aux violations CSP.

Déboguer les problèmes liés aux Trusted Types

Sans les bons outils pour les développeurs, il peut être difficile de travailler à grande échelle avec un testeur de confiance.

Amélioration de l'impression dans la console

Lorsque nous travaillons avec des objets de confiance, nous souhaitons afficher au moins la même quantité d'informations que les homologues non approuvés. Malheureusement, aucune information sur l'objet encapsulé ne s'affiche actuellement lors de l'affichage d'un objet de confiance.

C'est parce que la valeur affichée dans la console provient de l'appel de .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. À la place, nous aimerions disposer d'un résultat semblable à celui que vous obtenez lorsque vous appelez .toString(). Pour ce faire, nous devons modifier V8 et Blink afin d'introduire une gestion spéciale pour les objets de type de confiance.

Bien que, pour des raisons historiques, ce traitement personnalisé ait été effectué dans la version 8, une telle approche présente d'importants inconvénients. De nombreux objets nécessitent un affichage personnalisé, mais leur type est le même au niveau JS. Étant donné que V8 est en JavaScript pur, il ne peut pas distinguer les concepts correspondant à une API Web, tels que le type de confiance. C'est pourquoi V8 doit demander à son intégrateur (Blink) de les distinguer.

Par conséquent, déplacer cette partie du code vers Blink ou un autre intégrateur semble être un choix logique. Outre le problème exposé, les fonctionnalités suivantes offrent de nombreux autres avantages:

  • Chaque intégrateur peut générer sa propre 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.

Cas de non-respect des règles (en mode signalement uniquement)

Actuellement, le seul moyen de déboguer les cas de non-respect du TTT consiste à définir des points d'arrêt sur les exceptions JS. Étant donné que les cas de non-respect des règles du TT forcés déclenchent une exception, cette fonctionnalité peut s'avérer utile. Toutefois, dans des scénarios réels, vous avez besoin d'un contrôle plus précis des cas de non-respect des règles TT. En particulier, nous souhaitons que les coupures ne concernent que les cas de non-respect du TT (pas les autres exceptions) et en mode "Signalement uniquement".

Les outils de développement sont déjà compatibles avec une grande variété de points d'arrêt. L'architecture est donc assez extensible. Pour ajouter un type de point d'arrêt, vous devez modifier le backend (Blink), la CDP et l'interface. Nous devons introduire une nouvelle commande CDP que nous appelons setBreakOnTTViolation. L'interface utilisera cette commande pour indiquer au backend le type de non-respect des règles TT qui doit être rompue. Le backend, en particulier InspectorDOMDebuggerAgent, fournira une "vérification" onTTViolation() qui sera appelée chaque fois qu'un non-respect des règles TTC se produit. Ensuite, InspectorDOMDebuggerAgent vérifie si cette violation doit déclencher un point d'arrêt et, le cas échéant, envoie un message à l'interface pour suspendre l'exécution.

Qu'est-ce qui a été fait et que se passera-t-il ensuite ?

Depuis que les problèmes décrits ici ont été introduits, un certain nombre de modifications ont été apportées à l'onglet Problèmes:

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

Télécharger les canaux de prévisualisation

Vous pouvez utiliser Chrome Canary, Dev ou Bêta comme navigateur de développement par défaut. Ces versions preview vous permettent d'accéder aux dernières fonctionnalités des outils de développement, de tester des API de plates-formes Web de pointe et de 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 et des modifications dans l'article, ou de tout autre sujet lié aux outils de développement.

  • Envoyez-nous une suggestion ou un commentaire via crbug.com.
  • Signalez un problème lié aux outils de développement en cliquant sur Autres options   Plus > Aide > Signalez un problème dans les outils de développement.
  • Tweetez à l'adresse @ChromeDevTools.
  • Faites-nous part de vos commentaires sur les vidéos YouTube sur les nouveautés des outils de développement ou sur les vidéos YouTube de conseils pour les outils de développement.