Implementazione del debug CSP e TrustedType in Chrome DevTools

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

Questo post del blog riguarda l'implementazione del supporto di DevTools per il debug dei problemi relativi ai criteri di sicurezza del contenuto (CSP) con l'aiuto della scheda Problemi introdotta di recente.

I lavori di implementazione sono stati eseguiti nel corso di due stage: 1. Durante la prima, abbiamo sviluppato il framework generale di segnalazione e progettato i messaggi relativi a 3 violazioni delle norme CSP. 2. Nel secondo, abbiamo aggiunto i problemi di Trusted Type e alcune funzionalità DevTools specializzate per il debug di Trusted Type.

Che cos'è un criterio di sicurezza del contenuto?

Il Criterio di sicurezza del contenuto (CSP) consente di limitare determinati comportamenti in un sito web per aumentare la sicurezza. Ad esempio, CSP può essere utilizzato per non consentire gli script in linea o per non consentire eval, entrambi i quali riducono la superficie di attacco per gli attacchi di cross-site scripting (XSS). Per un'introduzione dettagliata ai CSP, leggi qui.

Un CSP particolarmente nuovo è il criterio Trusted Types(TT), che consente un'analisi dinamica che può impedire sistematicamente una vasta classe di attacchi di inserimento sui siti web. A questo scopo, TT supporta un sito web nella verifica del proprio codice JavaScript in modo da consentire l'assegnazione solo di determinati tipi di elementi ai sink DOM, come innerHTML.

Un sito web può attivare un criterio di sicurezza dei contenuti includendo una determinata intestazione HTTP. Ad esempio, l'intestazione content-security-policy: require-trusted-types-for 'script'; trusted-types default attiva il criterio TT per una pagina.

Ogni criterio può funzionare in una di queste modalità:

  • modalità applicata: ogni violazione delle norme è un errore,
  • Modalità solo report: il messaggio di errore viene segnalato come avviso, ma non causa un errore nella pagina web.

Implementazione dei problemi relativi ai criteri di sicurezza del contenuto nella scheda Problemi

L'obiettivo di questo lavoro era migliorare l'esperienza di debug per i problemi CSP. Quando prende in considerazione nuovi problemi, il team di DevTools segue approssimativamente questa procedura:

  1. Definizione delle storie utente. Identifica un insieme di storie utente nel front-end di DevTools che descriva in che modo uno sviluppatore web dovrebbe esaminare il problema.
  2. Implementazione del frontend. In base alle storie utente, identifica quali informazioni sono necessarie per esaminare il problema nel front-end (ad es. una richiesta correlata, il nome di un cookie, una riga in uno script o un file HTML e così via).
  3. Rilevamento dei problemi. Identifica i punti del browser in cui il problema può essere rilevato in Chrome e strumentalizza il punto per segnalare un problema, incluse le informazioni pertinenti del passaggio 2.
  4. Salva e visualizza i problemi. Archivia i problemi in una posizione appropriata e rendili disponibili a DevTools una volta aperto
  5. Progettazione del testo dei problemi. Crea un testo esplicativo che aiuti lo sviluppatore web a comprendere e, soprattutto, a risolvere il problema

Passaggio 1: definizione delle user story per i problemi relativi ai fornitori di servizi cloud

Prima di iniziare la nostra attività di implementazione, abbiamo creato un documento di progettazione contenente storie utente per capire meglio cosa dovevamo fare. Ad esempio, abbiamo scritto la seguente storia utente:


In qualità di sviluppatore, che si è appena reso conto che alcune parti del mio sito web sono bloccate, voglio:- - ...scoprire se CSP è un motivo che causa il blocco di iframe / immagini sul mio sito web - ...scoprire quale direttiva CSP causa il blocco di una determinata risorsa - ...sapere come modificare il CSP del mio sito web per consentire la visualizzazione delle risorse attualmente bloccate / l'esecuzione del codice JavaScript attualmente bloccato.


Per esplorare questa user story, abbiamo creato alcune semplici pagine web di esempio che presentavano le violazioni del CSP che ci interessavano ed esplorato le pagine di esempio per familiarizzare con la procedura. Ecco alcune pagine web di esempio (apri la demo con la scheda Problemi aperta):

Utilizzando questa procedura, abbiamo appreso che la posizione della sorgente era la più importante per il debug dei problemi relativi ai CSP. Abbiamo anche trovato utile trovare rapidamente l'iframe e la richiesta associati nel caso in cui una risorsa fosse bloccata e che un link diretto all'elemento HTML nel riquadro Elementi di DevTools potesse essere utile.

Passaggio 2: implementazione del front-end

Abbiamo trasformato queste informazioni nella prima bozza delle informazioni che volevamo rendere disponibili per DevTools tramite il Chrome DevTools Protocol (CDP):

Di seguito è riportato l'estratto da 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 definizione riportata sopra codifica essenzialmente una struttura di dati JSON. È scritto in un linguaggio semplice chiamato PDL (Protocol Data Language). Il PDL viene utilizzato per due scopi. Innanzitutto, utilizziamo PDL per generare le definizioni di TypeScript su cui si basa il front-end di DevTools. Ad esempio, la definizione PDL precedente genera la seguente interfaccia TypeScript:

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

In secondo luogo, e probabilmente più importante, generiamo una libreria C++ dalla definizione che gestisce la generazione e l'invio di queste strutture di dati dal backend di Chromium C++ al frontend di DevTools. Utilizzando questa libreria, è possibile creare un oggetto ContentSecurityPolicyIssueDetails utilizzando la seguente porzione di codice C++:

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

Una volta stabilite le informazioni che volevamo rendere disponibili, dovevamo capire dove trovarle in Chromium.

Passaggio 3: rilevamento dei problemi

Per rendere le informazioni disponibili per il protocollo Chrome DevTools (CDP) nel formato descritto nell'ultima sezione, dovevamo trovare il punto in cui le informazioni erano effettivamente disponibili nel back-end. Fortunatamente, il codice CSP aveva già un collo di bottiglia utilizzato per la modalità solo report, a cui potevamo collegarci: ContentSecurityPolicy::ReportViolation segnala i problemi a un endpoint di generazione di report (facoltativo) che può essere configurato nell'intestazione HTTP CSP. La maggior parte delle informazioni che volevamo segnalare era già disponibile, quindi non sono state necessarie grandi modifiche al back-end per il funzionamento della nostra strumentazione.

Passaggio 4: salva e visualizza i problemi

Una piccola complicazione è che volevamo anche segnalare i problemi che si sono verificati prima dell'apertura di DevTools, in modo simile alla gestione dei messaggi della console. Ciò significa che non segnaliamo immediatamente i problemi al front-end, ma utilizziamo uno spazio di archiviazione in cui vengono inseriti i problemi indipendentemente dal fatto che DevTools sia aperto o meno. Una volta aperto DevTools (o collegato qualsiasi altro client CDP), tutti i problemi registrati in precedenza possono essere riprodotti dallo spazio di archiviazione.

Questo ha concluso il lavoro sul backend e ora dovevamo concentrarci su come mostrare il problema nel frontend.

Passaggio 5: progettazione del testo dei problemi

La progettazione del testo dei problemi è un processo che coinvolge diversi team oltre al nostro. Ad esempio, spesso ci affidiamo alle informazioni del team che implementa una funzionalità (in questo caso il team CSP) e, ovviamente, il team DevRel, che progetta il modo in cui gli sviluppatori web dovrebbero affrontare un certo tipo di problema. Il testo del problema viene generalmente perfezionato fino al completamento.

Di solito il team di DevTools inizia con una bozza di ciò che immagina:


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

Dopo l'iterazione, siamo arrivati a:

ALT_TEXT_HERE

Come puoi vedere, il coinvolgimento del team delle funzionalità e di DevRel rende la descrizione molto più chiara e precisa.

I problemi relativi ai CSP sulla tua pagina sono disponibili anche nella scheda specificamente dedicata alle violazioni CSP.

Eseguire il debug dei problemi di Trusted Types

Lavorare con i TT su larga scala può essere complicato senza gli strumenti per sviluppatori giusti.

Stampa della console migliorata

Quando lavoriamo con oggetti attendibili, vogliamo mostrare almeno la stessa quantità di informazioni della controparte non attendibile. Purtroppo, al momento, quando viene visualizzato un oggetto attendibile non vengono visualizzate informazioni sull'oggetto con wrapping.

Questo perché il valore visualizzato nella console viene preso dalla chiamata a .valueOf() sull'oggetto per impostazione predefinita. Tuttavia, nel caso di Tipo attendibile, il valore restituito non è molto utile. Vorremmo invece avere qualcosa di simile a quello che ottieni quando chiami .toString(). Per farlo, dobbiamo modificare V8 e Blink per introdurre un'elaborazione speciale per gli oggetti di tipo attendibile.

Anche se per motivi storici questa gestione personalizzata è stata eseguita in V8, questo approccio presenta svantaggi importanti. Esistono molti oggetti che richiedono una visualizzazione personalizzata, ma il cui tipo è lo stesso a livello di JS. Poiché V8 è un JS puro, non è in grado di distinguere i concetti che corrispondono a un'API web, ad esempio un Trusted Type. Per questo motivo, V8 deve chiedere all'utente che ha caricato il video (Blink) di aiutarti a distinguerli.

Pertanto, spostare questa parte di codice in Blink o in qualsiasi altro embedder sembra una scelta logica. Oltre al problema esposto, ci sono molti altri vantaggi:

  • Ogni inserzionista può avere la propria generazione di descrizioni
  • È molto più facile generare la descrizione tramite l'API Blink
  • Blink ha accesso alla definizione originale dell'oggetto. Pertanto, se utilizziamo .toString() per generare la descrizione, non c'è rischio che .toString() venga ridefinito.

Interrompi in caso di violazione (in modalità solo report)

Al momento, l'unico modo per eseguire il debug delle violazioni dei token di transizione è impostare i breakpoint sulle eccezioni JS. Poiché le violazioni delle norme relative ai TT applicate comportano un'eccezione, questa funzionalità può essere in qualche modo utile. Tuttavia, negli scenari reali è necessario un controllo più granulare sulle violazioni delle norme relative ai contenuti. In particolare, vorremmo eseguire l'interruzione solo in caso di violazioni del TdR (non di altre eccezioni), anche in modalità solo report e distinguere tra i diversi tipi di violazioni del TdR.

DevTools supporta già un'ampia gamma di breakpoint, quindi l'architettura è abbastanza estensibile. L'aggiunta di un nuovo tipo di punto di interruzione richiede modifiche al backend (Blink), CDP e frontend. Dovremmo introdurre un nuovo comando CDP, chiamiamolo setBreakOnTTViolation. Questo comando verrà utilizzato dal frontend per indicare al backend quali tipi di violazioni del TT devono essere interrotte. Il backend, in particolare InspectorDOMDebuggerAgent, fornirà un "probe" (onTTViolation()) che verrà chiamato ogni volta che si verifica una violazione TT. InspectorDOMDebuggerAgent verificherà quindi se la violazione deve attivare un punto di interruzione e, in questo caso, invierà un messaggio al frontend per mettere in pausa l'esecuzione.

Cosa si fa e cosa si può fare dopo?

Da quando sono stati introdotti i problemi qui descritti, la scheda Problemi ha subito alcune modifiche:

In futuro, prevediamo di utilizzare la scheda Problemi per mostrare altri problemi, il che consentirà di scaricare dalla console il flusso di messaggi di errore illeggibili nel lungo periodo.

Scaricare i canali di anteprima

Valuta la possibilità di utilizzare Chrome Canary, Dev o Beta come browser di sviluppo predefinito. Questi canali di anteprima ti danno accesso alle ultime funzionalità di DevTools, ti consentono di testare le API delle piattaforme web all'avanguardia e ti aiutano a individuare i problemi sul tuo sito prima che lo facciano gli utenti.

Contatta il team di Chrome DevTools

Utilizza le seguenti opzioni per discutere di nuove funzionalità, aggiornamenti o qualsiasi altro argomento relativo a DevTools.