Debugging von CSP und vertrauenswürdigen Typen in den Chrome-Entwicklertools implementieren

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

In diesem Blogpost geht es um die Implementierung der Unterstützung für die Entwicklertools zum Debuggen von Problemen mit der Content Security Policy (CSP) mithilfe des kürzlich eingeführten Tabs Probleme.

Die Implementierung erfolgte in zwei Praktika: 1. Im ersten Schritt haben wir das Framework für die allgemeine Berichterstattung erstellt und die Problemmeldungen für drei Probleme mit CSP-Verstößen entwickelt. 2. Im zweiten Beispiel haben wir Probleme mit vertrauenswürdigen Typen sowie einige spezielle Entwicklertools-Funktionen zur Fehlerbehebung für vertrauenswürdige Typen hinzugefügt.

Was ist eine Content Security Policy?

Mit der Content Security Policy (CSP) können bestimmte Verhaltensweisen auf einer Website eingeschränkt werden, um die Sicherheit zu erhöhen. CSP kann beispielsweise verwendet werden, um Inline-Scripts oder eval nicht zuzulassen. Beide Methoden verringern die Angriffsfläche für Cross-Site-Scripting-Angriffe (XSS). Eine ausführliche Einführung in die CSP finden Sie hier.

Eine besonders neue CSP ist die Richtlinie TrustedTypes(TT), die eine dynamische Analyse ermöglicht, mit der eine große Klasse von Injection-Angriffen auf Websites systematisch verhindert werden kann. Um dies zu erreichen, unterstützt TT eine Website bei der Überwachung ihres JavaScript-Codes, damit nur bestimmte Arten von Dingen DOM-Senken zugewiesen werden können, wie z. B. innerHTML.

Eine Website kann eine Content Security Policy aktivieren, indem sie einen bestimmten HTTP-Header einfügt. Der Header content-security-policy: require-trusted-types-for 'script'; trusted-types default aktiviert beispielsweise die TT-Richtlinie für eine Seite.

Jede Richtlinie kann in einem der folgenden Modi ausgeführt werden:

  • erzwungenen Modus – jeder Richtlinienverstoß ist ein Fehler.
  • Nur-Berichtsmodus – In diesem Modus wird die Fehlermeldung als Warnung angezeigt, sie verursacht aber keinen Fehler auf der Webseite.

Probleme mit der Content Security Policy auf dem Tab Probleme implementieren

Ziel dieser Arbeit war es, die Fehlerbehebung für CSP-Probleme zu verbessern. Bei der Prüfung neuer Probleme folgt das Team für Entwicklertools grob:

  1. User Storys definieren Identifizieren Sie eine Reihe von User Storys im Frontend der Entwicklertools, die zeigen, wie Webentwickler das Problem untersuchen müssen.
  2. Frontend-Implementierung Identifizieren Sie anhand der User Stories, welche Informationen zur Untersuchung des Problems im Frontend erforderlich sind (z. B. eine ähnliche Anfrage, der Name eines Cookies, eine Zeile in einem Skript oder einer HTML-Datei usw.).
  3. Problemerkennung: Ermitteln Sie die Stellen im Browser, an denen das Problem in Chrome erkannt werden kann, und geben Sie an, wo es das Problem melden kann, einschließlich der relevanten Informationen aus Schritt 2.
  4. Speichere die Probleme und zeige sie an. Speichere die Probleme an einem geeigneten Ort und stelle sie für die Entwicklertools zur Verfügung, sobald sie geöffnet sind
  5. Problemtext entwerfen: Einen erklärenden Text verfassen, der dem Webentwickler hilft, das Problem zu verstehen und vor allem zu beheben

Schritt 1: User Storys für CSP-Probleme definieren

Bevor wir mit der Implementierung begannen, haben wir ein Designdokument mit User Storys erstellt, um besser zu verstehen, was wir tun mussten, beispielsweise die folgende User Story:


Als Entwickler, dem gerade klar wurde, dass ein Teil meiner Website blockiert ist, möchte ich:- - ... herausfinden, ob die CSP ein Grund für das Blockieren von iFrames/Bildern auf meiner Website ist - ...herausfinden, welche CSP-Anweisung zur Sperrung einer bestimmten Ressource führt - ... die CSP meiner Website ändern, um die Anzeige von derzeit blockierten Ressourcen bzw. die Ausführung derzeit blockierter JS zu ermöglichen.


Um diese User Story besser zu verstehen, haben wir einige einfache Beispielwebseiten erstellt, auf denen die CSP-Verstöße aufgezeigt wurden, für die wir interessiert waren. Außerdem haben wir uns die Beispielseiten angesehen, um uns mit dem Prozess vertraut zu machen. Hier sind einige der Beispielwebseiten. Öffnen Sie die Demo bei geöffnetem Tab Probleme:

So erfuhren wir, dass der Speicherort der Quelle die wichtigste Information bei der Behebung von CSP-Problemen ist. Außerdem fanden wir es hilfreich, den zugehörigen iFrame und die zugehörige Anfrage schnell zu finden, falls eine Ressource blockiert wurde. Auch ein direkter Link zum HTML-Element im Bereich Elemente der Entwicklertools könnte hilfreich sein.

Schritt 2: Frontend-Implementierung

Diese Informationen haben wir in den ersten Entwurf der Informationen umgewandelt, die wir den Entwicklertools über das Chrome DevTools Protocol (CDP) zur Verfügung stellen wollten:

Unten finden Sie den Auszug aus 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

Die obige Definition codiert im Wesentlichen eine JSON-Datenstruktur. Sie wird in einer einfachen Sprache geschrieben, die als PDL (Protokolldatensprache) bezeichnet wird. Die teilweise Domainlizenzierung wird für zwei Zwecke verwendet. Zunächst generieren wir mithilfe der PDL die TypeScript-Definitionen, von denen das DevTools-Frontend abhängig ist. Die obige PDL-Definition generiert beispielsweise die folgende TypeScript-Schnittstelle:

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

Zweitens, und was vermutlich noch wichtiger ist, generieren wir aus der Definition eine C++-Bibliothek, die das Generieren und Senden dieser Datenstrukturen vom C++ Chromium-Backend an das Frontend der Entwicklertools übernimmt. Mithilfe dieser Bibliothek kann mit dem folgenden C++-Code ein ContentSecurityPolicyIssueDetails-Objekt erstellt werden:

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

Nachdem wir uns entschieden hatten, welche Informationen wir zur Verfügung stellen wollten, mussten wir herausfinden, wo wir diese Informationen von Chromium erhalten.

Schritt 3: Problemerkennung

Um die Informationen in dem im letzten Abschnitt beschriebenen Format für das Chrome DevTools Protocol (CDP) verfügbar zu machen, mussten wir die Stelle im Backend finden, an der die Informationen tatsächlich verfügbar waren. Glücklicherweise hatte der CSP-Code bereits einen Engpass, der im „Nur Berichtsmodus“-Modus genutzt wurde. Dadurch konnten wir Folgendes verbinden: ContentSecurityPolicy::ReportViolation meldet Probleme einem (optionalen) Endpunkt für die Berichterstellung, der im CSP-HTTP-Header konfiguriert werden kann. Die meisten der Informationen, die wir melden wollten, waren bereits verfügbar, sodass keine größeren Änderungen im Backend nötig waren, damit unsere Instrumentierung funktionierte.

Schritt 4: Probleme speichern und anzeigen

Eine kleine Komplikation ist, dass wir auch Probleme melden wollten, die vor dem Öffnen der Entwicklertools aufgetreten sind, ähnlich wie bei Konsolennachrichten. Das bedeutet, dass wir Probleme nicht sofort an das Frontend melden, sondern einen Speicher verwenden, der mit Problemen gefüllt ist, unabhängig davon, ob die Entwicklertools geöffnet sind oder nicht. Sobald die Entwicklertools geöffnet sind (oder, falls ein anderer CDP-Client angehängt ist), können alle zuvor aufgezeichneten Probleme aus dem Speicher noch einmal abgespielt werden.

Damit war die Backend-Arbeit abgeschlossen und wir mussten uns nun darauf konzentrieren, wie das Problem im Frontend identifiziert werden kann.

Schritt 5: Problemtext entwerfen

Das Entwerfen des Problemtextes ist ein Prozess, an dem neben unserem Team mehrere Teams beteiligt sind. Beispielsweise stützen wir uns oft auf Erkenntnisse des Teams, das eine Funktion implementiert (in diesem Fall das CSP-Team), und natürlich vom DevRel-Team, das entwickelt, wie Webentwickler mit einem bestimmten Problem umgehen sollen. Der Problemtext wird in der Regel optimiert, bis er abgeschlossen ist.

Normalerweise beginnt das Entwicklungsteam mit einem groben Entwurf dessen, was es sich vorstellt:


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

Nach der Iteration kamen wir auf:

ALT_TEXT_HERE

Wie Sie sehen, ist die Beschreibung viel klarer und präziser, wenn Sie das Feature-Team und DevRel einbeziehen.

Sie finden CSP-Probleme auf Ihrer Seite auch auf dem Tab speziell für CSP-Verstöße.

Probleme mit vertrauenswürdigen Typen beheben

Die Arbeit mit TT in großem Umfang kann ohne die richtigen Entwicklertools eine Herausforderung sein.

Verbessertes Drucken über die Konsole

Wenn wir mit vertrauenswürdigen Objekten arbeiten, möchten wir mindestens die gleiche Menge an Informationen wie für das nicht vertrauenswürdige Gegenstück anzeigen. Wenn ein vertrauenswürdiges Objekt angezeigt wird, werden derzeit leider keine Informationen zum umschlossenen Objekt angezeigt.

Das liegt daran, dass der in der Konsole angezeigte Wert standardmäßig aus dem Aufruf von .valueOf() für das Objekt stammt. Beim vertrauenswürdigen Typ ist der zurückgegebene Wert jedoch nicht sehr hilfreich. Wir möchten Ihnen stattdessen etwas Ähnliches mitteilen, das Sie beim Aufrufen von .toString() erhalten. Um dies zu erreichen, müssen wir V8 und Blink ändern, um eine spezielle Behandlung für vertrauenswürdige Typobjekte einzuführen.

Obwohl diese benutzerdefinierte Verarbeitung aus historischen Gründen in V8 erfolgt ist, hat ein solcher Ansatz wichtige Nachteile. Es gibt viele Objekte, die eine benutzerdefinierte Anzeige erfordern, deren Typ aber auf JS-Ebene identisch ist. Da V8 reines JS ist, kann es nicht zwischen Konzepten unterscheiden, die einer Web-API wie etwa dem vertrauenswürdigen Typ entsprechen. Aus diesem Grund muss V8 den eingebetteten Einbettungscode (Blink) um Hilfe bitten, um sie zu unterscheiden.

Daher klingt es nach einer logischen Entscheidung, diesen Teil des Codes auf Blink oder einen anderen Einbettungscode zu übertragen. Neben diesem Problem gibt es noch viele weitere Vorteile:

  • Jeder Einbettunger kann eine eigene Beschreibungsgenerierung haben
  • Es ist viel einfacher, die Beschreibung über die Blink API zu generieren
  • Blink hat Zugriff auf die ursprüngliche Definition des Objekts. Wenn also .toString() zum Generieren der Beschreibung verwendet wird, besteht kein Risiko, dass .toString() neu definiert wird.

Verstoß (im Modus „Nur Berichterstellung“)

Derzeit besteht die einzige Möglichkeit zum Beheben von TT-Verstößen darin, Haltepunkte für JS-Ausnahmen festzulegen. Da erzwungene TT-Verstöße eine Ausnahme auslösen, kann diese Funktion hilfreich sein. In der Praxis benötigen Sie jedoch eine genauere Kontrolle über die Richtlinienverstöße. Wir möchten insbesondere bei Verstößen gegen die YouTube-Richtlinien eine Ausnahme machen, aber auch im Nur-Bericht-Modus und unterscheiden zwischen den verschiedenen Arten von TT-Verstößen.

Die Entwicklertools unterstützen bereits eine Vielzahl von Haltepunkten, sodass die Architektur recht erweiterbar ist. Das Hinzufügen eines neuen Haltepunkttyps erfordert Änderungen im Backend (Blink), CDP und am Frontend. Wir sollten einen neuen CDP-Befehl einführen, nennen wir ihn setBreakOnTTViolation. Mit diesem Befehl teilt das Backend dem Backend mit, welche Art von TT-Verstößen behoben werden sollen. Das Back-End, insbesondere InspectorDOMDebuggerAgent, stellt eine Prüfung (onTTViolation()) bereit, die jedes Mal aufgerufen wird, wenn ein TT-Verstoß auftritt. Anschließend prüft InspectorDOMDebuggerAgent, ob dieser Verstoß einen Haltepunkt auslösen soll. Ist dies der Fall, wird eine Nachricht an das Front-End gesendet, um die Ausführung anzuhalten.

Wie geht es weiter?

Seit der Einführung der hier beschriebenen Probleme wurden am Tab Probleme einige Änderungen vorgenommen:

Wir planen, den Tab Issues (Probleme in Zukunft) zu verwenden, um mehr Probleme aufzudecken. Dadurch wird es möglich sein, die nicht lesbaren Fehlermeldungen in der Konsole zu entfernen.

Vorschaukanäle herunterladen

Sie können Chrome Canary, Dev oder Beta als Standardbrowser für die Entwicklung verwenden. Über diese Vorschaukanäle erhältst du Zugriff auf die neuesten Entwicklertools-Funktionen, kannst neue Webplattform-APIs testen und Probleme auf deiner Website erkennen, bevor deine Nutzer es tun.

Chrome-Entwicklertools-Team kontaktieren

Verwende die folgenden Optionen, um die neuen Funktionen und Änderungen im Beitrag oder andere Themen im Zusammenhang mit den Entwicklertools zu besprechen.

  • Sende uns über crbug.com Vorschläge oder Feedback.
  • Wenn du ein Problem mit den Entwicklertools melden möchtest, klicke in den Entwicklertools auf Weitere Optionen   Mehr   > Hilfe > Probleme mit den Entwicklertools melden.
  • Senden Sie einen Tweet an @ChromeDevTools.
  • Hinterlasse Kommentare zu den Neuheiten in den Entwicklertools YouTube-Videos oder YouTube-Videos in den Entwicklertools-Tipps.