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.

Il lavoro di implementazione è stato svolto nel corso di due tirocini: 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 usato per non consentire gli script incorporati o per non consentire eval, entrambi riducendo la superficie di attacco per gli attacchi Cross-Site Scripting (XSS). Per un'introduzione dettagliata a CSP, leggi qui.

Un nuovo criterio CSP è il criterio Trusted Types(TT), che consente un'analisi dinamica in grado di prevenire sistematicamente un'ampia classe di attacchi di injection 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 del contenuto includendo una determinata intestazione HTTP. Ad esempio, l'intestazione content-security-policy: require-trusted-types-for 'script'; trusted-types default il criterio TT per una pagina.

Ogni criterio può operare in una delle seguenti modalità:

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

Implementazione di 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 valuta i nuovi problemi, il team DevTools segue approssimativamente questa procedura:

  1. Definizione delle storie utente. Identifica una serie di storie utente nel front-end di DevTools per sapere in che modo uno sviluppatore web dovrebbe analizzare il problema.
  2. Implementazione front-end. In base alle storie utente, identifica le informazioni necessarie per analizzare 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 è possibile rilevare il problema in Chrome e indica il luogo in cui segnalare il problema includendo le informazioni pertinenti del passaggio (2).
  4. Salva e visualizza i problemi. Archivia i problemi in un posto appropriato e rendili disponibili a DevTools una volta aperto
  5. Progettazione del testo dei problemi. Prepara un testo esplicativo che aiuti lo sviluppatore web a capire e, soprattutto, a risolvere il problema

Passaggio 1: definisci le storie utente per i problemi CSP

Prima di iniziare l'implementazione, abbiamo creato un documento di progettazione con storie degli utenti per capire meglio cosa dovevamo fare. Ad esempio, abbiamo scritto la seguente storia utente:


In qualità di sviluppatore, visto che alcune parti del mio sito web sono bloccate, vorrei: - ...scopri se CSP è un motivo per cui iframe / immagini bloccati sul mio sito web - ...scopri quale direttiva CSP causa il blocco di una determinata risorsa - ...sapere come cambiare il CSP del mio sito web per consentire la visualizzazione delle risorse attualmente bloccate / l'esecuzione del codice JavaScript attualmente bloccato.


Per esplorare questa storia utente, abbiamo creato alcune semplici pagine web di esempio che presentavano le violazioni dei contenuti CSP che ci interessavano. Inoltre, abbiamo esplorato le pagine di esempio per acquisire familiarità con la procedura. Ecco alcune pagine web di esempio (apri la demo con la scheda Problemi aperta):

Grazie a questo processo, abbiamo capito che la località di origine era l'informazione più importante per il debug dei problemi CSP. Inoltre, abbiamo trovato utile trovare rapidamente l'iframe e la richiesta associati nel caso in cui una risorsa fosse bloccata, nonché l'utilizzo di un link diretto all'elemento HTML nel riquadro Elements di DevTools.

Passaggio 2: implementazione front-end

Abbiamo trasformato questi approfondimenti nella prima bozza delle informazioni che volevamo rendere disponibili a DevTools tramite il protocollo DevTools (CDP) di Chrome:

Di seguito è riportato un 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 precedente codifica essenzialmente una struttura di dati JSON. È scritto in un linguaggio semplice chiamato PDL (protocollo data language). Il PDL viene usato per due scopi. Innanzitutto, utilizziamo il modello 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 front-end 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();

Dopo aver stabilito quali informazioni rendere disponibili, abbiamo dovuto capire dove recuperare queste informazioni da Chromium.

Passaggio 3: rilevamento dei problemi

Per rendere le informazioni disponibili per il protocollo (CDP) di Chrome DevTools nel formato descritto nella sezione precedente, dovevamo trovare il punto in cui le informazioni erano effettivamente disponibili nel backend. Fortunatamente, il codice CSP aveva già un collo di bottiglia utilizzato per la modalità solo report, al quale potevamo collegarsi a: ContentSecurityPolicy::ReportViolation segnala i problemi a un endpoint di reporting (facoltativo) che può essere configurato nell'intestazione HTTP CSP. La maggior parte delle informazioni che volevamo comunicare erano già disponibili, quindi non sono stati necessari grandi cambiamenti a livello di back-end per far funzionare la nostra strumentazione.

Passaggio 4: salva e visualizza i problemi

Una piccola complicazione è il fatto che volevamo segnalare anche 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 popolato da problemi indipendentemente dal fatto che DevTools sia aperto o meno. Una volta aperto DevTools (o, per questa ragione, è collegato qualsiasi altro client CDP), tutti i problemi registrati in precedenza possono essere riprodotti dallo spazio di archiviazione.

Abbiamo concluso il lavoro di back-end e ora dobbiamo concentrarci su come far emergere il problema nel front-end.

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. In genere, il testo del problema viene perfezionato fino al completamento.

Di solito il team 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 della tua pagina sono disponibili anche nella scheda specificamente dedicata alle violazioni CSP.

Debug dei problemi di Trusted Type

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

Stampa della console migliorata

Quando lavoriamo con oggetti attendibili, vorremmo mostrare almeno la stessa quantità di informazioni della controparte non attendibile. Purtroppo, al momento, quando si visualizza un oggetto attendibile, non vengono visualizzate informazioni sull'oggetto aggregato.

Il motivo è che il valore visualizzato nella console deriva dalla chiamata a .valueOf() sull'oggetto per impostazione predefinita. Tuttavia, nel caso di Trusted Type, il valore restituito non è molto utile. Vorremmo invece avere qualcosa di simile a quello che ricevi quando chiami .toString(). Per ottenere questo risultato, dobbiamo modificare V8 e Blink per introdurre una gestione speciale per gli oggetti di tipo attendibile.

Sebbene, per motivi storici questa gestione personalizzata sia stata eseguita nella versione V8, un approccio del genere presenta importanti svantaggi. Esistono molti oggetti che richiedono la visualizzazione personalizzata, ma il cui tipo è lo stesso a livello di JavaScript. 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 quella parte del codice in Blink o in un qualsiasi incorporamento sembra una scelta logica. Oltre al problema esposto, ci sono molti altri vantaggi:

  • Ogni autore incorporato può avere la propria generazione di descrizioni
  • È molto più semplice 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'è alcun rischio che .toString() possa essere ridefinito.

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

Attualmente, l'unico modo per eseguire il debug delle violazioni TT è impostare i punti di interruzione nelle eccezioni JS. Poiché le violazioni delle norme relative ai TT applicate comporteranno un'eccezione, questa funzionalità può essere in qualche modo utile. Tuttavia, in scenari reali è necessario un controllo più granulare sulle violazioni del TT. In particolare, vorremmo interrompere solo in caso di violazioni del TT (Non altre eccezioni), rompere anche in modalità di solo segnalazione e distinguere tra i diversi tipi di violazioni del TT.

DevTools supporta già un'ampia gamma di punti di interruzione, pertanto l'architettura è piuttosto estensibile. L'aggiunta di un nuovo tipo di punto di interruzione richiede modifiche al backend (Blink), CDP e frontend. Occorre introdurre un nuovo comando CDP, chiamiamolo setBreakOnTTViolation. Questo comando verrà utilizzato dal frontend per indicare al backend il tipo di violazioni TT che deve interrompere. Il backend, in particolare InspectorDOMDebuggerAgent, fornirà un "probe" (onTTViolation()) che verrà chiamato ogni volta che si verifica una violazione TT. InspectorDOMDebuggerAgent verificherà 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 far emergere altri problemi, il che a lungo termine consentirà di annullare il caricamento della console del flusso di messaggi di errore illeggibili.

Scaricare i canali in anteprima

Prendi in considerazione l'utilizzo di Chrome Canary, Dev o Beta come browser di sviluppo predefinito. Questi canali di anteprima ti consentono di accedere alle funzionalità più recenti di DevTools, testare le API delle piattaforme web all'avanguardia e individuare i problemi sul tuo sito prima che lo facciano gli utenti.

Contattare il team di Chrome DevTools

Utilizza le seguenti opzioni per discutere delle nuove funzionalità e modifiche nel post o di qualsiasi altra informazione relativa a DevTools.

  • Inviaci un suggerimento o un feedback tramite crbug.com.
  • Segnala un problema di DevTools utilizzando Altre opzioni   Altro > Guida > Segnala un problema di DevTools in DevTools.
  • Invia un tweet all'indirizzo @ChromeDevTools.
  • Lascia commenti sulle novità nei video di YouTube di DevTools o nei video di YouTube dei suggerimenti di DevTools.