In diesem Blogpost geht es um die Implementierung der DevTools-Unterstützung für das Debugging von Problemen mit der Content Security Policy (CSP) mithilfe des kürzlich eingeführten Tabs Probleme.
Die Implementierung wurde im Rahmen von zwei Praktika durchgeführt: 1. In der ersten Phase haben wir das allgemeine Berichts-Framework erstellt und die Problemmeldungen für drei CSP-Verstöße entworfen. 2. In der zweiten Phase haben wir Trusted Type-Probleme sowie einige spezielle DevTools-Funktionen für das Trusted Types-Debugging hinzugefügt.
Was ist eine Content Security Policy?
Mit der Content Security Policy (CSP) können Sie bestimmte Verhaltensweisen auf einer Website einschränken, um die Sicherheit zu erhöhen. Beispielsweise kann die CSP verwendet werden, um Inline-Scripts oder eval zu verbieten. Beides reduziert die Angriffsfläche für Cross-Site-Scripting-Angriffe (XSS-Angriffe). Eine ausführliche Einführung in CSP finden Sie hier.
Eine besonders neue CSP ist die Richtlinie Trusted Types(TT), die eine dynamische Analyse ermöglicht, mit der eine große Klasse von Injection-Angriffen auf Websites systematisch verhindert werden kann. Dazu unterstützt TT eine Website bei der Überwachung ihres JavaScript-Codes, damit nur bestimmte Arten von Elementen DOM-Senken wie innerHTML zugewiesen werden können.
Eine Website kann eine Content Security Policy aktivieren, indem sie einen bestimmten HTTP-Header einfügt. Beispielsweise aktiviert der Header content-security-policy: require-trusted-types-for 'script'; trusted-types default die TT-Richtlinie für eine Seite.
Jede Richtlinie kann in einem der folgenden Modi ausgeführt werden:
- Erzwungener Modus: Jeder Richtlinienverstoß ist ein Fehler.
- Nur-Berichtsmodus: Die Fehlermeldung wird als Warnung gemeldet, führt aber nicht zu einem Fehler auf der Webseite.
Probleme bei der Implementierung der Content Security Policy auf dem Tab Probleme
Ziel dieser Arbeit war es, das Debugging von CSP-Problemen zu verbessern. Bei der Prüfung neuer Probleme geht das DevTools-Team in etwa so vor:
- User Storys definieren: Identifizieren Sie eine Reihe von User Storys im DevTools-Frontend, die beschreiben, wie ein Webentwickler das Problem untersuchen müsste.
- Frontend-Implementierung: Ermitteln Sie anhand der User Stories, welche Informationen für die Untersuchung des Problems im Frontend erforderlich sind (z. B. eine zugehörige Anfrage, der Name eines Cookies, eine Zeile in einem Skript oder einer HTML-Datei usw.).
- Problemerkennung: Ermitteln Sie die Stellen im Browser, an denen das Problem in Chrome erkannt werden kann, und richten Sie die Stelle so ein, dass ein Problem mit den relevanten Informationen aus Schritt (2) gemeldet wird.
- Speichern Sie die Probleme und lassen Sie sie anzeigen. Probleme an einem geeigneten Ort speichern und den Entwicklertools zur Verfügung stellen, sobald sie geöffnet werden
- Text für Probleme entwerfen Erstellen Sie einen erklärenden Text, der dem Webentwickler hilft, das Problem zu verstehen und vor allem zu beheben.
Schritt 1: User Stories für CSP-Probleme definieren
Bevor wir mit der Implementierung begonnen haben, haben wir ein Designdokument mit User Storys erstellt, um besser zu verstehen, was wir tun müssen. Wir haben zum Beispiel die folgende User Story aufgeschrieben:
As a developer, who just realized that some part of my website are blocked, I want to:- - ...find out if CSP is a reason for blocked iframes / images on my website - ...learn which CSP directive causes the blockage of a certain resource - ...know how to change the CSP of my website to allow display of currently blocked resources / execution of currently blocked js.
Um diese User Story zu untersuchen, haben wir einige einfache Beispiel-Webseiten erstellt, die die CSP-Verstöße aufwiesen, die uns interessierten. Wir haben die Beispielseiten untersucht, um uns mit dem Prozess vertraut zu machen. Hier sind einige Beispielwebseiten (öffnen Sie die Demo mit geöffnetem Tab Probleme):
Dabei haben wir festgestellt, dass der Quellspeicherort die wichtigste Information für die Fehlerbehebung bei CSP-Problemen ist. Wir fanden es auch nützlich, den zugehörigen iFrame und die Anfrage schnell zu finden, falls eine Ressource blockiert wurde. Ein direkter Link zum HTML-Element im Bereich Elemente der DevTools könnte ebenfalls nützlich sein.
Schritt 2: Frontend-Implementierung
Diese Erkenntnis haben wir in den ersten Entwurf der Informationen einfließen lassen, die wir den Entwicklertools über das Chrome-Entwicklertools-Protokoll (CDP) zur Verfügung stellen wollten:
Unten sehen 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. PDL wird für zwei Zwecke verwendet. Zuerst verwenden wir PDL, um die TypeScript-Definitionen zu generieren, auf die das DevTools-Frontend angewiesen 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 wahrscheinlich noch wichtiger, generieren wir aus der Definition eine C++-Bibliothek, die diese Datenstrukturen generiert und vom C++-Chromium-Backend an das DevTools-Frontend sendet. Mit dieser Bibliothek kann ein ContentSecurityPolicyIssueDetails-Objekt mit dem folgenden C++-Code 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 darauf geeinigt hatten, welche Informationen wir zur Verfügung stellen wollten, mussten wir herausfinden, wo wir diese Informationen in Chromium finden.
Schritt 3: Problemerkennung
Damit die Informationen dem Chrome-Entwicklertools-Protokoll (CDP) im im letzten Abschnitt beschriebenen Format zur Verfügung gestellt werden können, mussten wir die Stelle finden, an der die Informationen im Back-End tatsächlich verfügbar waren. Glücklicherweise gab es im CSP-Code bereits einen Engpass, der für den Nur-Berichterstellung-Modus verwendet wurde und in den wir uns einklinken konnten: ContentSecurityPolicy::ReportViolation meldet Probleme an einen (optionalen) Berichts-Endpunkt, der im CSP-HTTP-Header konfiguriert werden kann. Die meisten Informationen, die wir melden wollten, waren bereits verfügbar. Daher waren keine großen Änderungen im Backend erforderlich, damit unsere Instrumentierung funktioniert.
Schritt 4: Probleme speichern und anzeigen
Eine kleine Komplikation ist, dass wir auch Probleme melden wollten, die vor dem Öffnen der DevTools aufgetreten sind, ähnlich wie bei Konsolennachrichten. Das bedeutet, dass Probleme nicht sofort an das Frontend gemeldet werden, sondern in einem Speicher abgelegt werden, der unabhängig davon, ob die DevTools geöffnet sind oder nicht, mit Problemen gefüllt wird. Sobald die Entwicklertools geöffnet sind (oder ein anderer CDP-Client verbunden ist), können alle zuvor aufgezeichneten Probleme aus dem Speicher wiedergegeben werden.
Damit war die Arbeit am Backend abgeschlossen und wir mussten uns nun darauf konzentrieren, wie wir das Problem im Frontend darstellen können.
Schritt 5: Text für die Probleme entwerfen
Die Erstellung des Textes für die Probleme ist ein Prozess, an dem neben unserem eigenen Team mehrere Teams beteiligt sind. Wir verlassen uns beispielsweise oft auf die Erkenntnisse des Teams, das eine Funktion implementiert (in diesem Fall das CSP-Team), und natürlich des DevRel-Teams, das festlegt, wie Webentwickler mit einer bestimmten Art von Problem umgehen sollen. Der Text des Problems wird in der Regel mehrmals überarbeitet, bis er fertig ist.
In der Regel beginnt das DevTools-Team mit einem groben Entwurf seiner Vorstellungen:
## 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 sind wir zu folgendem Ergebnis gekommen:

Wie Sie sehen, wird die Beschreibung durch die Einbeziehung des Feature-Teams und von DevRel viel klarer und präziser.
CSP-Probleme auf Ihrer Seite finden Sie auch auf dem Tab, der speziell für CSP-Verstöße vorgesehen ist.
Debugging von Trusted Types-Problemen
Die Arbeit mit TT in großem Umfang kann ohne die richtigen Entwicklertools eine Herausforderung sein.
Verbesserte Ausgabe in der Konsole
Wenn wir mit vertrauenswürdigen Objekten arbeiten, möchten wir mindestens so viele Informationen wie für das nicht vertrauenswürdige Gegenstück anzeigen. Leider werden derzeit beim Anzeigen eines vertrauenswürdigen Objekts keine Informationen zum verpackten Objekt angezeigt.
Das liegt daran, dass der in der Konsole angezeigte Wert standardmäßig durch den Aufruf von .valueOf() für das Objekt abgerufen wird. Im Fall von Trusted Type ist der zurückgegebene Wert jedoch nicht sehr nützlich. Stattdessen möchten wir etwas Ähnliches wie das, was Sie beim Aufrufen von .toString() erhalten. Dazu müssen wir V8 und Blink so ändern, dass vertrauenswürdige Typobjekte speziell behandelt werden.
Aus historischen Gründen wurde diese benutzerdefinierte Verarbeitung zwar in V8 durchgeführt, ein solcher Ansatz hat jedoch erhebliche Nachteile. Es gibt viele Objekte, die eine benutzerdefinierte Darstellung erfordern, deren Typ auf JS-Ebene jedoch identisch ist. Da V8 reines JS ist, kann es keine Konzepte unterscheiden, die einer Web-API wie einem Trusted Type entsprechen. Aus diesem Grund muss V8 seinen Embedder (Blink) um Hilfe bitten, um sie zu unterscheiden.
Daher ist es sinnvoll, diesen Teil des Codes nach Blink oder einen anderen Embedder zu verschieben. Abgesehen von dem Problem, das wir aufgedeckt haben, gibt es viele weitere Vorteile:
- Jeder Embedder kann eine eigene Beschreibung generieren.
- 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
.toString()verwenden, um die Beschreibung zu generieren, besteht kein Risiko, dass.toString()neu definiert wird.
Unterbrechung bei Verstoß (im Modus „Nur Berichterstellung“)
Derzeit ist die einzige Möglichkeit, TT-Verstöße zu debuggen, das Festlegen von Haltepunkten für JS-Ausnahmen. Da erzwungene TT-Verstöße eine Ausnahme auslösen, kann diese Funktion nützlich sein. In der Praxis benötigen Sie jedoch eine genauere Kontrolle über TT-Verstöße. Insbesondere möchten wir nur bei TT-Verstößen (nicht bei anderen Ausnahmen) unterbrechen, auch im Modus „Nur Berichterstellung“ unterbrechen und zwischen den verschiedenen Arten von TT-Verstößen unterscheiden.
Die DevTools unterstützen bereits eine Vielzahl von Haltepunkten, sodass die Architektur recht erweiterbar ist. Wenn Sie einen neuen Haltepunkttyp hinzufügen möchten, müssen Sie Änderungen im Backend (Blink), im CDP und im Frontend vornehmen.
Wir sollten einen neuen CDP-Befehl einführen, nennen wir ihn setBreakOnTTViolation. Dieser Befehl wird vom Frontend verwendet, um dem Backend mitzuteilen, bei welchen Arten von TT-Verstößen es abbrechen soll. Das Backend, insbesondere InspectorDOMDebuggerAgent, stellt eine „Probe“ (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. Wenn ja, wird eine Nachricht an das Frontend gesendet, um die Ausführung zu pausieren.
Was ist erledigt und was steht als Nächstes an?
Seit die hier beschriebenen Probleme aufgetreten sind, hat sich der Tab Probleme stark verändert:
- Die Verknüpfung mit anderen Bereichen in den DevTools wurde verbessert.
- Die Meldung einer Reihe weiterer Probleme wurde auf den Tab Probleme verschoben: u. a. geringer Kontrast, vertrauenswürdige Web-Aktivität, Quirks-Modus, Attribution Reporting API und CORS-bezogene Probleme.
- Es wurde die Möglichkeit eingeführt, Probleme auszublenden.
In Zukunft möchten wir den Tab Probleme verwenden, um mehr Probleme anzuzeigen. So können wir die Konsole langfristig von unlesbaren Fehlermeldungen entlasten.
Vorschaukanäle herunterladen
Verwenden Sie Chrome Canary, Dev oder Beta als Standardbrowser für die Entwicklung. Über diese Vorabversionen erhalten Sie Zugriff auf die neuesten DevTools-Funktionen, können innovative Webplattform-APIs testen und Probleme auf Ihrer Website finden, bevor Ihre Nutzer sie bemerken.
Chrome-Entwicklertools-Team kontaktieren
Nutzen Sie die folgenden Optionen, um über die neuen Funktionen, Updates oder andere Themen im Zusammenhang mit den Entwicklertools zu diskutieren.
- Feedback und Feature Requests können Sie unter crbug.com einreichen.
- Sie können ein Problem mit den Entwicklertools melden, indem Sie in den Entwicklertools auf das Dreipunkt-Menü Weitere Optionen > Hilfe > Problem mit den Entwicklertools melden klicken.
- Tweeten Sie an @ChromeDevTools.
- Hinterlassen Sie Kommentare zu den YouTube-Videos What's new in DevTools oder DevTools Tips.