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) que nous avons récemment présenté.

Le travail d'implémentation a été réalisé au cours de deux stages : 1. Lors de la première, nous avons créé le framework général de création de rapports et conçu les messages correspondant à trois cas de non-respect des CSP. 2. Lors de la deuxième, nous avons ajouté les problèmes liés aux Trusted Types, ainsi que des fonctionnalités d'outils de développement dédiées au 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 afin de renforcer la sécurité. Par exemple, CSP peut être utilisé pour interdire les scripts intégrés ou pour interdire eval, ce qui permet de réduire la surface d'attaque pour les attaques par script intersites (XSS). Pour obtenir une présentation détaillée de CSP, cliquez ici.

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

Un site Web peut activer une stratégie de sécurité du contenu en incluant un en-tête HTTP spécifique. 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 appliqué : chaque cas de non-respect des règles correspond à une erreur.
  • Rapport uniquement : le message d'erreur est considéré comme un avertissement, mais ne provoque pas d'échec sur la page Web.

Implémenter les problèmes Content Security Policy dans l'onglet Issues (Problèmes)

L'objectif de ce travail était d'améliorer l'expérience de débogage des problèmes liés à CSP. Lorsqu'elle examine de nouveaux problèmes, l'équipe des outils de développement suit globalement la procédure suivante:

  1. Définir les histoires d'utilisateurs Dans l'interface des outils de développement, identifiez un ensemble d'histoires utilisateur expliquant comment un développeur Web devrait examiner le problème.
  2. Implémentation de l'interface. Sur la base des histoires d’utilisateurs, identifiez les éléments d’information nécessaires pour enquêter sur le problème dans l’interface (par exemple, une demande 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 emplacements du navigateur où le problème peut être détecté dans Chrome et indiquez-leur où signaler le problème, y compris les informations pertinentes de l'étape 2.
  4. Enregistrez les problèmes et affichez-les. Stockez les problèmes dans un endroit approprié et mettez-les à la disposition des outils de développement une fois qu'ils sont ouverts.
  5. Concevoir le texte des problèmes proposer un texte explicatif qui aide le développeur Web à comprendre et, plus important encore, à résoudre le problème.

Étape 1: Définir les histoires d'utilisateurs pour les problèmes liés aux FSC

Avant de commencer notre travail d'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 noté le récit utilisateur suivant:


En tant que développeur, je viens de réaliser qu'une partie de mon site Web est bloquée, et je souhaite:- - ...déterminer si CSP est à l'origine du blocage des iFrames / images sur mon site Web - ...savoir quelle directive CSP provoque 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 de JavaScript actuellement bloqué.


Pour explorer cette histoire d’utilisateur, nous avons créé quelques exemples de pages Web simples qui présentent les cas de non-respect des CSP qui nous intéressaient, et nous avons examiné ces exemples pour nous familiariser nous-mêmes avec le processus. Voici quelques exemples de pages Web (ouvrez la démo avec l'onglet Problèmes):

Grâce à ce processus, nous avons appris que l'emplacement source était l'information la plus importante pour déboguer les problèmes liés à CSP. Nous avons également trouvé utile de trouver rapidement l'iFrame associé et la requête en cas de blocage d'une ressource. De plus, il peut être utile d'ajouter un lien direct vers l'élément HTML dans le panneau Elements (Éléments) des outils de développement.

Étape 2: Implémenter l'interface

Nous avons fait de ces insights la première ébauche des informations que nous voulions mettre à la disposition des outils de développement 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 (protocole de données de protocole). PDL est utilisé à deux fins. Tout d'abord, nous utilisons PDL pour générer les définitions TypeScript sur lesquelles s'appuie 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;
}

Ensuite, et c'est probablement le plus important, 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 C++ de Chromium vers l'interface DevTools. À l'aide de cette bibliothèque, un objet ContentSecurityPolicyIssueDetails peut être créé à l'aide du 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 choisi les informations que nous voulions mettre à disposition, nous avons dû chercher où les obtenir à partir de Chromium.

Étape 3: Détecter les problèmes

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

Étape 4: Enregistrez les problèmes et affichez-les

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 traités. Cela signifie que nous ne signalons pas immédiatement les problèmes à l'interface, mais que nous utilisons un espace de stockage contenant des problèmes, que les outils de développement soient ouverts ou non. Une fois les outils de développement ouverts (ou, éventuellement, tout autre client CDP associé), tous les problèmes précédemment enregistrés peuvent être relancés à partir de l'espace de stockage.

Le travail backend est maintenant terminé. Nous devions maintenant nous concentrer sur la façon de faire apparaître le problème dans l'interface.

Étape 5: Concevoir le texte sur les problèmes

La conception du texte des problèmes est un processus impliquant plusieurs équipes autres que la nôtre. Par exemple, nous nous appuyons souvent sur les insights de l'équipe qui met en œuvre une fonctionnalité (dans ce cas, l'équipe CSP) et, bien sûr, de l'équipe DevRel, qui conçoit la façon dont les développeurs Web sont censés traiter un certain type de problème. Le texte du problème doit généralement être affiné jusqu'à ce qu'il soit terminé.

Généralement, l'équipe des outils de développement 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, faire appel à l'équipe chargée de la fonctionnalité et aux développeurs DevRel rend la description beaucoup plus claire et précise.

Les problèmes liés à CSP sur votre page sont également visibles dans l'onglet spécifiquement dédié aux cas de non-respect de CSP.

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

Sans les bons outils pour les développeurs, il peut s'avérer difficile d'utiliser le synthèse vocale à grande échelle.

Amélioration de l'impression de la console

Lorsque nous utilisons des objets de confiance, nous souhaitons afficher au moins la même quantité d'informations que pour les autres. Malheureusement, actuellement, lors de l'affichage d'un objet de confiance, aucune information sur l'objet encapsulé n'est affichée.

Cela est dû au fait que la valeur affichée dans la console provient par défaut de l'appel de .valueOf() sur l'objet. Cependant, dans le cas du type de confiance, la valeur renvoyée n'est pas très utile. Nous aimerions plutôt disposer d'informations semblables à celles que vous obtenez lorsque vous appelez .toString(). Pour ce faire, nous devons modifier V8 et Blink afin d'introduire un traitement spécial pour les objets de type approuvé.

Bien que ce traitement personnalisé ait été effectué dans V8 pour des raisons historiques, cette approche présente d'importants inconvénients. De nombreux objets nécessitent un affichage personnalisé, mais dont le type est identique au niveau JavaScript. Étant donné que V8 est un code JavaScript pur, il ne peut pas distinguer des concepts correspondant à une API Web telle qu'un Trusted Type. V8 doit donc demander à son outil d'intégration (Blink) de les distinguer.

Par conséquent, déplacer cette partie du code vers Blink ou tout composant intégré semble être un choix logique. Outre le problème exposé, il existe 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.

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

À l'heure actuelle, le seul moyen de déboguer les cas de non-respect des règles de correspondance du protocole consiste à définir des points d'arrêt au niveau des exceptions JavaScript. Étant donné que les cas de non-respect des règles de validation forcée déclenchent une exception, cette fonctionnalité peut s'avérer utile. Toutefois, en situation réelle, vous avez besoin d'un contrôle plus précis des cas de non-respect du règlement relatif aux cookies. En particulier, nous aimerions briser uniquement les cas de non-respect du règlement relatif au ciblage par mots clés (et non les autres exceptions), rompre également le mode "rapports uniquement" et faire la distinction entre les différents types de non-respect du règlement du programme.

Les outils de développement sont déjà compatibles avec une grande variété de points d'arrêt, de sorte que l'architecture est assez extensible. L'ajout d'un nouveau type de point d'arrêt nécessite de modifier le backend (Blink), la CDP et l'interface. Nous devrions introduire une nouvelle commande CDP, que nous appellerons setBreakOnTTViolation. Cette commande sera utilisée par l'interface pour indiquer au backend le type de non-respect des règles de validation qui doit être rompu. Le backend, en particulier InspectorDOMDebuggerAgent, fournira une "vérification", onTTViolation() qui sera appelée à chaque fois qu'une violation 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 à l'interface pour suspendre l'exécution.

Que faire et quelle est la prochaine étape ?

Depuis que nous avons présenté les problèmes décrits ici, l'onglet Problèmes a subi de nombreuses modifications:

À l'avenir, nous prévoyons d'utiliser l'onglet Issues (Problèmes) pour afficher d'autres 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

Nous vous conseillons d'utiliser Chrome Canary, Dev ou Beta 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 pointe de plates-formes Web et de détecter les problèmes sur votre site avant qu'ils ne le fassent.

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 toute autre question concernant les outils de développement.

  • Envoyez-nous une suggestion ou des commentaires via crbug.com.
  • Signalez un problème dans les outils de développement via Plus d'options   More > Aide > Signaler un problème dans les outils de développement dans les Outils de développement.
  • Envoyez un tweet à @ChromeDevTools.
  • Dites-nous en plus sur les nouveautés concernant les vidéos YouTube dans les outils de développement ou sur les vidéos YouTube de nos conseils relatifs aux outils de développement.