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 des Supports der Entwicklertools zum Beheben von Problemen mit der Content Security Policy (CSP) mithilfe des kürzlich eingeführten Tabs Probleme.

Die Implementierung erfolgte im Verlauf von zwei Praktika: 1. Beim ersten haben wir ein allgemeines Framework für die Berichterstellung entwickelt und die Problemmeldungen für drei Probleme bei CSP-Verstößen entwickelt. 2. Beim zweiten Mal haben wir neben einigen speziellen Entwicklertools für das Debugging für vertrauenswürdige Typen auch Probleme mit vertrauenswürdigen 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. Beispielsweise kann die CSP verwendet werden, um Inline-Scripts oder eval zu verbieten. Beide Optionen verringern die Angriffsfläche für Cross-Site Scripting (XSS)-Angriffe. Eine detaillierte Einführung in CSP finden Sie hier.

Eine besonders neue CSP ist die Richtlinie Vertrauenswürdige Typen(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, sodass nur bestimmte Arten von Dingen DOM-Senken wie innerHTML zugewiesen werden können.

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

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

  • enforced mode (erzwungener Modus) – hier ist jeder Richtlinienverstoß ein Fehler.
  • Nur Berichtsmodus: In diesem Modus wird die Fehlermeldung als Warnung ausgegeben, 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 Berücksichtigung neuer Probleme verfolgt das Entwicklertools-Team ungefähr diesen Prozess:

  1. User Storys definieren. Identifizieren Sie eine Reihe von User Stories im DevTools-Frontend, die beschreiben, wie Webentwickler das Problem untersuchen müssen.
  2. Frontend-Implementierung Ermitteln Sie anhand der User Stories, welche Informationen für die Untersuchung des Problems im Frontend erforderlich sind (z. B. eine entsprechende Anfrage, der Name eines Cookies, eine Zeile in einer Skript- oder HTML-Datei usw.).
  3. Problemerkennung: Suchen Sie die Stellen im Browser, an denen das Problem in Chrome erkannt werden kann, und geben Sie die entsprechenden Informationen aus Schritt 2 an, um das Problem zu melden.
  4. Speichern Sie die Probleme und rufen Sie sie auf. Probleme an einem geeigneten Ort speichern und nach dem Öffnen den Entwicklertools zur Verfügung stellen
  5. Problemtext entwerfen: Erstellen Sie einen erklärenden Text, der dem Webentwickler hilft, das Problem zu verstehen und – noch wichtiger – 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 haben wir die folgende User Story niedergeschrieben:


Als Entwickler, der gerade festgestellt hat, dass ein Teil meiner Website blockiert ist, möchte ich Folgendes tun: - ...herausfinden, ob CSP ein Grund für blockierte iFrames / Bilder auf meiner Website ist - ...lesen, welche CSP-Anweisung die Blockierung einer bestimmten Ressource verursacht – ...wissen, wie ich die CSP meiner Website so ändern kann, dass derzeit blockierte Ressourcen angezeigt bzw. derzeit blockierte JS ausgeführt werden.


Um diese User Story zu untersuchen, haben wir einige einfache Beispielwebseiten erstellt, auf denen die für uns interessanten CSP-Verstöße zu sehen sind. Außerdem haben wir uns die Beispielseiten angesehen, um uns mit dem Prozess vertraut zu machen. Hier sehen Sie einige der Beispielwebseiten. Öffnen Sie dazu die Demo und öffnen Sie den Tab Probleme:

Dabei haben wir festgestellt, dass der Quellspeicherort die wichtigste Information für die Fehlerbehebung bei CSP-Problemen ist. Wir fanden es auch hilfreich, den zugehörigen iFrame und die Anfrage schnell zu finden, falls eine Ressource blockiert wurde, und dass ein direkter Link zum HTML-Element im Bereich Elements der Entwicklertools hilfreich sein könnte.

Schritt 2: Frontend-Implementierung

Wir haben diese Informationen in den ersten Entwurf der Informationen umgewandelt, die wir für die Entwicklertools über das Chrome DevTools Protocol (CDP) zur Verfügung stellen möchten:

Unten finden Sie einen 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 ist in einer einfachen Sprache namens PDL (Protocol Data Language) geschrieben. Die teilweise Domainlizenzierung wird für zwei Zwecke verwendet. Zuerst verwenden wir PDL, um die TypeScript-Definitionen zu generieren, auf die sich das Entwicklertools-Frontend stützt. 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, was wahrscheinlich noch wichtiger ist, generieren wir eine C++-Bibliothek aus der Definition, die das Generieren und Senden dieser Datenstrukturen vom C++ Chromium-Backend an das Entwicklertools-Frontend übernimmt. Mit dieser Bibliothek kann ein ContentSecurityPolicyIssueDetails-Objekt mit dem folgenden C++ Code-Snippet 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 beziehen können.

Schritt 3: Problemerkennung

Um die Informationen im Protokoll der Chrome-Entwicklertools (CDP) im im letzten Abschnitt beschriebenen Format zur Verfügung zu stellen, mussten wir im Backend ermitteln, wo die Informationen tatsächlich verfügbar waren. Glücklicherweise hatte der CSP-Code bereits einen Engpass für den Berichterstellungsmodus, bei dem Folgendes möglich ist: ContentSecurityPolicy::ReportViolation meldet Probleme an einen (optionalen) Endpunkt für die Berichterstellung, der im CSP-HTTP-Header konfiguriert werden kann. Die meisten Informationen, die wir berichten wollten, waren bereits verfügbar, sodass keine größeren Änderungen im Backend notwendig waren, damit unsere Instrumentierung funktioniert.

Schritt 4: Probleme speichern und anzeigen

Eine kleine Komplikation besteht darin, dass wir auch Probleme melden wollten, die vor dem Öffnen der Entwicklertools aufgetreten sind, ähnlich wie Konsolennachrichten verarbeitet werden. Das bedeutet, dass Probleme nicht sofort an das Frontend gemeldet werden, sondern ein Speicher mit Problemen verwendet wird – unabhängig davon, ob die Entwicklertools geöffnet sind oder nicht. Sobald die Entwicklertools geöffnet sind (oder, in diesem Fall mit einem anderen CDP-Client), können alle zuvor aufgezeichneten Probleme aus dem Speicher erneut abgespielt werden.

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

Schritt 5: Problemtext gestalten

Das Entwerfen des Problemtextes ist ein Prozess, an dem neben unserem eigenen auch 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 des DevRel-Teams, das entwirft, wie Webentwickler mit einem bestimmten Problemtyp umgehen sollen. Der Problemtext wird normalerweise optimiert, bis er fertig ist.

Normalerweise beginnt das DevTools-Team mit einer groben Vorstellung davon:


## 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 erhielten wir Folgendes:

ALT_TEXT_HERE

Wie Sie sehen, wird die Beschreibung durch die Einbeziehung des Feature-Teams und DevRel viel klarer und präziser!

CSP-Probleme auf Ihrer Seite können auch auf dem Tab speziell für CSP-Verstöße gefunden werden.

Probleme mit vertrauenswürdigen Typen beheben

Ohne die richtigen Entwicklertools kann die Arbeit mit TT in großem Umfang schwierig 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. Leider werden derzeit beim Anzeigen eines vertrauenswürdigen Objekts keine Informationen über das umschlossene Objekt angezeigt.

Das liegt daran, dass der in der Konsole angezeigte Wert standardmäßig vom Aufruf von .valueOf() für das Objekt übernommen wird. Im Fall eines vertrauenswürdigen Typs ist der zurückgegebene Wert jedoch nicht sehr nützlich. Stattdessen hätten wir etwas Ähnliches wie das erhalten, wenn du .toString() aufrufst. Um dies zu erreichen, müssen wir V8 und Blink ändern, um eine spezielle Behandlung für vertrauenswürdige Objekttypen einzuführen.

Aus historischen Gründen wurde diese kundenspezifische Verarbeitung zwar in V8 vorgenommen, diese Vorgehensweise hat jedoch erhebliche Nachteile. Es gibt viele Objekte, die eine benutzerdefinierte Anzeige erfordern, deren Typ jedoch auf JS-Ebene identisch ist. Da es sich bei V8 um reines JavaScript handelt, kann es nicht zwischen Konzepten unterscheiden, die einer Web-API entsprechen, wie z. B. einem vertrauenswürdigen Typ. Aus diesem Grund muss V8 den Einbettungsdienst (Blink) um Hilfe bei der Unterscheidung bitten.

Daher klingt es logisch, diesen Teil des Codes in „Blink“ oder einen Einbettungscode zu verschieben. Neben dem aufgezeigten Problem gibt es viele weitere Vorteile:

  • Für jeden Einbettungscode kann eine eigene Beschreibung generiert werden
  • Es ist viel einfacher, die Beschreibung über die Blink API zu generieren
  • Blink hat Zugriff auf die ursprüngliche Definition des Objekts. Wenn wir also die Beschreibung mit .toString() generieren, besteht kein Risiko, dass .toString() neu definiert wird.

Break-on-violation (im Berichterstellungsmodus)

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 nützlich sein. In der Praxis benötigen Sie jedoch eine präzisere Kontrolle über TT-Verstöße. Insbesondere möchten wir nur bei Verstößen gegen die TT (keine anderen Ausnahmen), die Sperrung auch im Berichtsmodus vornehmen und zwischen den verschiedenen Arten von TT-Verstößen unterscheiden.

Die Entwicklertools unterstützen bereits eine Vielzahl von Haltepunkten, sodass die Architektur ziemlich erweiterbar ist. Zum Hinzufügen eines neuen Haltepunkttyps sind Änderungen im Backend (Blink), CDP und am Frontend erforderlich. Wir sollten einen neuen CDP-Befehl einführen, den wir setBreakOnTTViolation nennen. Dieser Befehl wird vom Frontend verwendet, um dem Backend mitzuteilen, welche Art von TT-Verstößen nicht behoben werden soll. Das Back-End, insbesondere InspectorDOMDebuggerAgent, stellt eine "Prüfung" bereit, onTTViolation(), die jedes Mal aufgerufen wird, wenn ein TT-Verstoß auftritt. Anschließend prüft InspectorDOMDebuggerAgent, ob dieser Verstoß einen Haltepunkt auslöst. Ist dies der Fall, wird eine Nachricht an das Front-End gesendet, um die Ausführung zu pausieren.

Was wird erledigt und wie geht es weiter?

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

In Zukunft möchten wir den Tab Issues (Probleme) verwenden, um weitere Probleme anzuzeigen. Dadurch wird es möglich sein, die Konsole langfristig von dem nicht lesbaren Fehlermeldungenfluss zu entladen.

Vorschaukanäle herunterladen

Sie können Canary, Dev oder Beta als Standardbrowser für die Entwicklung verwenden. Über diese Vorschaukanäle erhalten Sie Zugriff auf die neuesten Entwicklertools, können innovative Webplattform-APIs testen und Probleme auf Ihrer Website erkennen, bevor Ihre Nutzer es tun.

Kontaktaufnahme mit dem Team für Chrome-Entwicklertools

Mit den folgenden Optionen kannst du die neuen Funktionen und Änderungen in dem Beitrag oder andere Aspekte der Entwicklertools besprechen.

  • Senden Sie uns über crbug.com einen Vorschlag oder Feedback.
  • Problem mit den Entwicklertools über Weitere Optionen melden Mehr > Hilfe > Hier kannst du Probleme mit den Entwicklertools in den Entwicklertools melden.
  • Twittern Sie unter @ChromeDevTools.
  • Hinterlasse Kommentare in den YouTube-Videos mit den Neuerungen in den Entwicklertools oder in YouTube-Videos mit Tipps zu den Entwicklertools.