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 explique comment implémenter la compatibilité des outils pour les développeurs avec le débogage des problèmes liés aux règles de sécurité du contenu (CSP) à l'aide de l'onglet Problèmes récemment introduit.

Le travail d'implémentation a été effectué au cours de deux stages : 1. Lors de la première, nous avons créé le framework de création de rapports général et conçu les messages de problème pour trois cas de non-respect des règles du CSP. 2. Lors de la seconde, nous avons ajouté des problèmes de type approuvé ainsi que certaines fonctionnalités DevTools spécialisées pour le débogage des types approuvés.

Qu'est-ce qu'une stratégie de sécurité du contenu ?

La stratégie de sécurité du contenu (CSP) permet de limiter certains comportements sur un site Web afin d'accroître la sécurité. Par exemple, vous pouvez utiliser une CSP 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 en savoir plus sur les CSP, cliquez ici.

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

Un site Web peut activer une stratégie 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 stratégie TT pour une page.

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

  • mode d'application : chaque non-respect des règles est une erreur.
  • Mode "report-only" (mode "signaler uniquement") : le message d'erreur est signalé en tant qu'avertissement, mais ne provoque pas d'échec sur la page Web.

Implémenter les problèmes liés à la stratégie de sécurité du contenu dans l'onglet Problèmes

L'objectif de ce travail était d'améliorer l'expérience de débogage pour les problèmes CSP. Lorsque l'équipe DevTools examine de nouveaux problèmes, elle suit approximativement ce processus:

  1. Définir des histoires d'utilisateurs Identifiez un ensemble d'histoires d'utilisateurs dans le front-end des outils de développement qui explique comment un développeur Web doit examiner le problème.
  2. Implémentation du front-end Sur la base des histoires d'utilisateurs, identifiez les informations requises pour examiner le problème dans le front-end (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 emplacements du navigateur où le problème peut être détecté dans Chrome et instrumentez-les pour signaler un problème, en incluant les informations pertinentes de l'étape 2.
  4. Enregistrez et affichez les problèmes. Stockez les problèmes dans un emplacement approprié et mettez-les à la disposition des outils de développement une fois qu'ils sont ouverts.
  5. Conception du texte des problèmes Rédigez un texte explicatif qui aide le développeur Web à comprendre et, surtout, à résoudre le problème.

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

Avant de commencer notre travail d'implémentation, nous avons créé un document de conception avec des histoires d'utilisateurs pour mieux comprendre ce que nous devions faire. Par exemple, nous avons rédigé l'histoire d'utilisateur suivante:


En tant que développeur, je viens de constater que certaines parties de mon site Web sont bloquées. Je souhaite:- معرفة ما إذا كان CSP est la raison pour laquelle les iFrames / images sont bloquées sur mon site Web - معرفة quelle directive CSP provoque le blocage d'une certaine ressource - معرفة كيفية تغيير CSP de mon site Web pour permettre l'affichage des ressources actuellement bloquées / l'exécution des fichiers JavaScript actuellement bloqués.


Pour explorer cette histoire d'utilisateur, nous avons créé des exemples de pages Web simples qui présentaient les cas de non-respect des règles CSP qui nous intéressaient. Nous avons ensuite exploré ces exemples pour nous familiariser avec le processus. Voici quelques exemples de pages Web (ouvrez la démonstration en laissant l'onglet Problèmes ouvert):

Grâce à ce processus, nous avons appris que l'emplacement de la source était l'information la plus importante pour déboguer les problèmes liés aux FSC. Nous avons également trouvé utile de trouver rapidement l'iframe et la requête associée en cas de blocage d'une ressource. Un lien direct vers l'élément HTML dans le panneau Éléments de DevTools pourrait également être utile.

Étape 2: Implémentation du front-end

Nous avons transformé cette information en première ébauche des informations que nous souhaitions mettre à la disposition de DevTools via le protocole Chrome DevTools (CDP):

Vous trouverez ci-dessous 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 PDL pour générer les définitions TypeScript sur lesquelles le front-end DevTools 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 plus important encore, 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 le frontend DevTools. À l'aide de cette bibliothèque, vous pouvez créer un objet ContentSecurityPolicyIssueDetails à 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 déterminé les informations que nous souhaitions mettre à disposition, nous avons dû déterminer où les trouver dans Chromium.

Étape 3: Détection des problèmes

Pour mettre les informations à la disposition du protocole CDP (Chrome DevTools Protocol) au format décrit dans la dernière section, nous avons dû trouver l'emplacement où elles étaient réellement disponibles dans le backend. Heureusement, le code du CSP comportait déjà un goulot d'étranglement utilisé pour le mode "Rapport uniquement", auquel nous pouvions nous connecter: ContentSecurityPolicy::ReportViolation signale les problèmes à un point de terminaison de création de rapports (facultatif) qui peut être configuré dans l'en-tête HTTP du CSP. La plupart des informations que nous souhaitions enregistrer étaient déjà disponibles. Par conséquent, aucune modification importante du backend n'était nécessaire pour que notre instrumentation fonctionne.

Étape 4: Enregistrez et affichez les problèmes

Nous souhaitions également signaler les problèmes qui se sont produits avant l'ouverture de DevTools, comme c'est le cas pour les messages de console. Cela signifie que nous ne signalons pas immédiatement les problèmes au niveau de l'interface utilisateur, mais que nous utilisons un espace de stockage qui est renseigné par les problèmes, que les outils de développement soient ouverts ou non. Une fois DevTools ouvert (ou tout autre client CDP associé), tous les problèmes précédemment enregistrés peuvent être rejoués à partir du stockage.

Le travail côté backend est terminé. Nous devons maintenant nous concentrer sur la façon de signaler le problème côté 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 façon 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 finalisé.

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 l'itération, nous sommes arrivés à:

ALT_TEXT_HERE

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

Vous pouvez également consulter les problèmes liés aux CSP sur votre page dans l'onglet dédié aux cas de non-respect des CSP.

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

Travailler avec le traitement de texte à grande échelle peut être difficile sans les bons outils de développement.

Amélioration de l'impression dans la console

Lorsque nous utilisons des objets approuvés, nous souhaitons afficher au moins la même quantité d'informations que pour leur équivalent non approuvé. Malheureusement, actuellement, aucune information sur l'objet encapsulé n'est affichée lorsque vous affichez un objet approuvé.

En effet, la valeur affichée dans la console est extraite de l'appel de .valueOf() sur l'objet par défaut. Toutefois, dans le cas du type de confiance, la valeur renvoyée n'est pas très utile. Nous aimerions plutôt obtenir quelque chose de semblable à ce 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 approuvés.

Bien que cette gestion personnalisée ait été effectuée dans V8 pour des raisons historiques, 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 du code JavaScript. Étant donné que V8 est du code JavaScript pur, il ne peut pas distinguer les concepts qui correspondent à une API Web, comme un type approuvé. C'est pourquoi V8 doit demander à son intégrateur (Blink) de l'aider à les distinguer.

Par conséquent, déplacer cette partie du code vers Blink ou tout autre outil d'intégration semble être un choix logique. En dehors du problème exposé, cette fonctionnalité présente 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. Par conséquent, si nous utilisons .toString() pour générer la description, il n'y a aucun risque que .toString() soit redéfini.

Arrêt en cas de non-respect (en mode "Rapport uniquement")

Actuellement, le seul moyen de déboguer les cas de non-respect des règles de temps de chargement consiste à définir des points d'arrêt sur les exceptions JavaScript. Étant donné que les cas de non-respect des règles de temps de travail 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 de TT. Plus précisément, nous souhaitons que la rupture ne se produise que pour les cas de non-respect des règles de temps de chargement (et non pour les autres exceptions), qu'elle se produise également en mode "Rapport uniquement" et qu'elle distingue les différents types de non-respect des règles de temps de chargement.

DevTools est déjà compatible avec un large éventail de points d'arrêt. L'architecture est donc très extensible. L'ajout d'un type de point d'arrêt nécessite des modifications dans le backend (Blink), le CDP et le frontend. Nous devrions introduire une nouvelle commande CDP, appelons-la setBreakOnTTViolation. Cette commande sera utilisée par le frontend pour indiquer au backend le type d'infractions de TT qu'il doit détecter. Le backend, en particulier InspectorDOMDebuggerAgent, fournit une "sonde", onTTViolation(), qui sera appelée chaque fois qu'une violation de TT se produit. InspectorDOMDebuggerAgent vérifie ensuite si cette infraction 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 se passe-t-il ensuite ?

Depuis l'apparition des problèmes décrits ici, l'onglet Problèmes a subi de nombreux changements:

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

Télécharger les canaux de prévisualisation

Envisagez d'utiliser Chrome Canary, Dev ou Bêta comme navigateur de développement par défaut. Ces canaux de prévisualisation vous donnent accès aux dernières fonctionnalités de DevTools, vous permettent de tester les 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 élément lié aux outils pour les développeurs.