Implementatie van foutopsporing voor CSP en vertrouwde typen in Chrome DevTools

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

Deze blogpost gaat over de implementatie van DevTools-ondersteuning voor het debuggen van Content Security Policy (CSP)-problemen met behulp van het onlangs geïntroduceerde tabblad Problemen .

Het implementatiewerk werd uitgevoerd in de loop van 2 stages: 1. Tijdens de eerste hebben we het algemene rapportageraamwerk gebouwd en de probleemberichten ontworpen voor 3 CSP-schendingskwesties. 2. Tijdens de tweede hebben we Trusted Type-problemen toegevoegd naast enkele gespecialiseerde DevTools-functies voor het opsporen van fouten in Trusted Types.

Wat is een inhoudbeveiligingsbeleid?

Content Security Policy (CSP) maakt het mogelijk om bepaald gedrag op een website te beperken om de veiligheid te vergroten. CSP kan bijvoorbeeld worden gebruikt om inline scripts of eval niet toe te staan, waardoor het aanvalsoppervlak voor Cross-Site Scripting (XSS) -aanvallen kleiner wordt. Voor een gedetailleerde introductie tot CSP kunt u hier lezen.

Een bijzonder nieuwe CSP is het Trusted Types(TT) -beleid, dat een dynamische analyse mogelijk maakt die systematisch een grote klasse injectie-aanvallen op websites kan voorkomen. Om dit te bereiken ondersteunt TT een website bij het toezicht houden op de JavaScript-code, zodat alleen bepaalde typen dingen aan DOM-sinks zoals innerHTML kunnen worden toegewezen.

Een website kan een inhoudbeveiligingsbeleid activeren door een bepaalde HTTP-header op te nemen. De header content-security-policy: require-trusted-types-for 'script'; trusted-types default het TT-beleid voor een pagina.

Elk beleid kan in een van deze modi werken:

  • afgedwongen modus - waarbij elke beleidsschending een fout is,
  • alleen-rapportmodus - die de foutmelding als waarschuwing rapporteert, maar geen fout op de webpagina veroorzaakt.

Problemen met het inhoudbeveiligingsbeleid implementeren op het tabblad Problemen

Het doel van dit werk was om de foutopsporingservaring voor CSP-problemen te verbeteren. Bij het overwegen van nieuwe problemen volgt het DevTools-team grofweg dit proces:

  1. Het definiëren van gebruikersverhalen . Identificeer een reeks gebruikersverhalen in de front-end van DevTools die beschrijven hoe een webontwikkelaar het probleem zou moeten onderzoeken.
  2. Front-end implementatie . Identificeer op basis van de gebruikersverhalen welke stukjes informatie nodig zijn voor onderzoek naar het probleem in de front-end (bijvoorbeeld een gerelateerd verzoek, de naam van een cookie, een regel in een script of HTML-bestand, enz.).
  3. Probleemdetectie . Identificeer de plaatsen in de browser waar het probleem kan worden gedetecteerd in Chrome en instrumenteer de plaats om een ​​probleem te melden, inclusief de relevante informatie uit stap (2).
  4. Bewaar en toon de problemen . Bewaar de problemen op een geschikte plaats en maak ze beschikbaar voor DevTools zodra ze zijn geopend
  5. Het ontwerpen van de tekst van het probleem . Bedenk een verklarende tekst die de webontwikkelaar helpt het probleem te begrijpen en, nog belangrijker, op te lossen

Stap 1: user stories definiëren voor CSP Issues

Voordat we met onze implementatiewerkzaamheden begonnen, hebben we een ontwerpdocument met gebruikersverhalen gemaakt om beter te begrijpen wat we moesten doen. We hebben bijvoorbeeld het volgende gebruikersverhaal opgeschreven:


Als ontwikkelaar, die zich net heeft gerealiseerd dat een deel van mijn website is geblokkeerd, wil ik:- - ...uitvinden of CSP een reden is voor geblokkeerde iframes/afbeeldingen op mijn website - ...leren welke CSP-richtlijn het probleem veroorzaakt blokkering van een bepaalde bron - ...weet hoe ik de CSP van mijn website moet wijzigen om weergave van momenteel geblokkeerde bronnen / uitvoering van momenteel geblokkeerde js mogelijk te maken.


Om dit gebruikersverhaal te verkennen, hebben we een aantal eenvoudige voorbeeldwebpagina's gemaakt waarop de CSP-schendingen te zien zijn waarin we geïnteresseerd waren, en hebben we de voorbeeldpagina's verkend om zelf vertrouwd te raken met het proces. Hier zijn enkele voorbeeldwebpagina's (open de demo met het tabblad Problemen geopend):

Met behulp van dit proces hebben we geleerd dat de bronlocatie het belangrijkste stukje informatie was voor het opsporen van fouten in CSP-problemen. We vonden het ook handig om snel het bijbehorende iframe en verzoek te vinden voor het geval een bron werd geblokkeerd, en dat een directe link naar het HTML-element in het Elements -paneel van DevTools ook nuttig zou kunnen zijn.

Stap 2: front-end implementatie

Dit inzicht hebben we omgezet in de eerste versie van de informatie die we via het Chrome DevTools Protocol (CDP) beschikbaar wilden stellen aan DevTools:

Hieronder vindt u het fragment uit 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

De bovenstaande definitie codeert in wezen een JSON-datastructuur. Het is geschreven in een eenvoudige taal genaamd PDL (protocoldatataal). PDL wordt voor twee doeleinden gebruikt. Ten eerste gebruiken we PDL om de TypeScript-definities te genereren waar de front-end van DevTools op vertrouwt. De bovenstaande PDL-definitie genereert bijvoorbeeld de volgende TypeScript-interface:

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

Ten tweede, en waarschijnlijk nog belangrijker, genereren we een C++-bibliotheek op basis van de definitie die het genereren en verzenden van deze datastructuren van de C++ Chromium-back-end naar de DevTools-front-end afhandelt. Met behulp van die bibliotheek kan een ContentSecurityPolicyIssueDetails -object worden gemaakt met behulp van het volgende stukje C++-code:

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

Toen we eenmaal hadden besloten welke informatie we beschikbaar wilden maken, moesten we onderzoeken waar we deze informatie uit Chromium konden halen.

Stap 3: probleemdetectie

Om de informatie beschikbaar te maken voor het Chrome DevTools Protocol (CDP) in het formaat dat in de vorige sectie is beschreven, moesten we de plaats vinden waar de informatie daadwerkelijk beschikbaar was in de back-end. Gelukkig had de CSP-code al een knelpunt dat werd gebruikt voor de alleen-rapportagemodus, waar we konden inhaken op: ContentSecurityPolicy::ReportViolation rapporteert problemen aan een (optioneel) rapportage-eindpunt dat kan worden geconfigureerd in de CSP HTTP-header . De meeste informatie die we wilden rapporteren was al beschikbaar, dus er waren geen grote veranderingen in de back-end nodig om onze instrumentatie te laten werken.

Stap 4: sla de problemen op en toon ze

Een kleine complicatie is het feit dat we ook problemen wilden melden die zich voordeden voordat DevTools werd geopend, vergelijkbaar met de manier waarop consoleberichten worden afgehandeld. Dit betekent dat we problemen niet direct aan de front-end melden, maar een opslag gebruiken die wordt gevuld met problemen, ongeacht of DevTools open is of niet. Zodra DevTools is geopend (of een andere CDP-client is aangesloten), kunnen alle eerder opgenomen problemen vanuit de opslag worden afgespeeld.

Hiermee was het back-endwerk afgerond en moesten we ons nu concentreren op hoe we het probleem aan de voorkant aan de oppervlakte konden brengen.

Stap 5: het ontwerpen van de tekst van het nummer

Het ontwerpen van de probleemtekst is een proces waarbij naast de onze ook meerdere teams betrokken zijn. We vertrouwen bijvoorbeeld vaak op inzicht van het team dat een functie implementeert (in dit geval zou dat het CSP-team zijn) en natuurlijk het DevRel-team, dat ontwerpt hoe webontwikkelaars met een bepaald type probleem moeten omgaan. De uitgavetekst ondergaat meestal enige verfijning totdat deze klaar is.

Meestal begint het DevTools-team met een ruwe schets van wat ze zich voorstellen:


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

Na iteratie kwamen we uit op:

ALT_TEXT_HIER

Zoals u kunt zien, maakt het betrekken van het featureteam en DevRel de beschrijving een stuk duidelijker en nauwkeuriger!

CSP-problemen op uw pagina kunnen ook worden ontdekt op het tabblad dat specifiek is gewijd aan CSP-schendingen .

Problemen met vertrouwde typen oplossen

Werken met TT op grote schaal kan een uitdaging zijn zonder de juiste ontwikkelaarstools.

Verbeterd afdrukken op de console

Wanneer we met Trusted Objects werken, willen we minimaal dezelfde hoeveelheid informatie weergeven als voor de niet-vertrouwde tegenhanger. Helaas wordt er momenteel bij het weergeven van een vertrouwd object geen informatie over het ingepakte object weergegeven.

Dit komt omdat de waarde die in de console wordt weergegeven, standaard wordt overgenomen van het aanroepen van .valueOf() op het object. In het geval van Trusted Type is de geretourneerde waarde echter niet erg nuttig. In plaats daarvan zouden we graag iets hebben dat lijkt op wat je krijgt als je .toString() aanroept. Om dit te bereiken moeten we V8 en Blink aanpassen om een ​​speciale behandeling voor vertrouwde typeobjecten te introduceren.

Hoewel deze aangepaste afhandeling om historische redenen in de V8 werd uitgevoerd, heeft een dergelijke aanpak belangrijke nadelen. Er zijn veel objecten die aangepaste weergave vereisen, maar waarvan het type hetzelfde is op JS-niveau. Omdat V8 pure JS is, kan het geen onderscheid maken tussen concepten die overeenkomen met een web-API, zoals een Trusted Type. Om die reden moet V8 de inbedder (Blink) om hulp vragen om ze te onderscheiden.

Daarom klinkt het verplaatsen van dat deel van de code naar Blink of een andere embedder als een logische keuze. Naast het blootgestelde probleem zijn er nog veel meer voordelen:

  • Elke insluiter kan zijn eigen beschrijvingsgeneratie hebben
  • Het is veel eenvoudiger om de beschrijving te genereren via de Blink API
  • Blink heeft toegang tot de originele definitie van het object. Als we dus .toString() gebruiken om de beschrijving te genereren, bestaat er geen risico dat .toString() opnieuw wordt gedefinieerd.

Break-on-schending (in alleen-rapportagemodus)

Momenteel is de enige manier om TT-schendingen op te sporen het instellen van breekpunten op JS-uitzonderingen. Omdat afgedwongen TT-schendingen een uitzondering zullen veroorzaken, kan deze functie op de een of andere manier nuttig zijn. In scenario's in de echte wereld heb je echter een meer fijnmazige controle over TT-overtredingen nodig. In het bijzonder willen we alleen de TT-overtredingen onderbreken (geen andere uitzonderingen), ook de rapporteringsmodus onderbreken en onderscheid maken tussen de verschillende soorten TT-overtredingen.

DevTools biedt al ondersteuning voor een breed scala aan breekpunten, dus de architectuur is behoorlijk uitbreidbaar. Het toevoegen van een nieuw breekpunttype vereist wijzigingen in de backend (Blink), CDP en de frontend. We zouden een nieuw CDP-commando moeten introduceren, laten we het setBreakOnTTViolation noemen. Dit commando zal door de frontend worden gebruikt om de backend te vertellen welke soort TT-overtredingen deze moet overtreden. De backend, in het bijzonder InspectorDOMDebuggerAgent , zal een "probe" bieden, onTTViolation() die elke keer dat er een TT-schending plaatsvindt, wordt aangeroepen. Vervolgens controleert InspectorDOMDebuggerAgent of die overtreding een breekpunt moet activeren, en als dat het geval is, stuurt het een bericht naar de frontend om de uitvoering te pauzeren.

Wat is er gedaan en wat nu?

Sinds de hier beschreven problemen zijn geïntroduceerd, heeft het tabblad Problemen nogal wat veranderingen ondergaan:

In de toekomst zijn we van plan het tabblad Problemen te gebruiken om meer problemen aan het licht te brengen, waardoor het op de lange termijn mogelijk wordt om de console te ontdoen van de onleesbare foutmeldingenstroom.

Download de voorbeeldkanalen

Overweeg om Chrome Canary , Dev of Beta te gebruiken als uw standaard ontwikkelingsbrowser. Met deze voorbeeldkanalen krijgt u toegang tot de nieuwste DevTools-functies, kunt u geavanceerde webplatform-API's testen en kunt u problemen op uw site opsporen voordat uw gebruikers dat doen!

Neem contact op met het Chrome DevTools-team

Gebruik de volgende opties om de nieuwe functies, updates of iets anders gerelateerd aan DevTools te bespreken.