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 2 tirocini: 1. Nel primo, abbiamo creato il framework generale per la generazione di report e progettato i messaggi relativi a 3 violazioni dei CSP. 2. Nel secondo, abbiamo aggiunto i problemi relativi a tipo attendibile insieme ad alcune funzionalità specifiche di DevTools per il debug di TrustedType.

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 incorporati o per non consentire eval, il che riduce la superficie di attacco per gli attacchi Cross-Site Scripting (XSS). Per un'introduzione dettagliata a CSP, leggi qui.

Un criterio CSP particolarmente nuovo è il criterio Trusted Tipi(TT), che consente un'analisi dinamica che può prevenire sistematicamente una grande classe di attacchi di iniezione sui siti web. Per raggiungere questo obiettivo, TT supporta un sito web per il controllo del codice JavaScript in modo da consentire solo l'assegnazione di determinati tipi di elementi ai sink DOM, ad esempio 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ò operare in una delle seguenti modalità:

  • modalità forzata, in cui ogni violazione delle norme è un errore
  • modalità di solo report: che segnala il messaggio di errore 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 dei problemi relativi a CSP. Durante la valutazione di nuovi problemi, il team DevTools segue approssimativamente questa procedura:

  1. Definizione delle storie degli utenti. Identifica un insieme di storie utente nel front-end DevTools che spiega in che modo uno sviluppatore web deve analizzare il problema.
  2. Implementazione frontend. Sulla base delle storie utente, identifica le informazioni necessarie per l'analisi del problema nel front-end (ad es. una richiesta correlata, il nome di un cookie, una riga di 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 imposta il luogo per segnalare un problema, includendo le informazioni pertinenti del passaggio (2).
  4. Salva e visualizza i problemi. Archivia i problemi in una posizione appropriata e rendili disponibili in DevTools una volta aperti
  5. Progettare il testo dei problemi. Prepara un testo esplicativo che aiuti lo sviluppatore web a capire e, ancora più importante, a risolvere il problema.

Passaggio 1: definizione delle storie degli utenti per i problemi relativi ai CSP

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


In qualità di sviluppatore, che ha appena capito che alcune parti del mio sito web sono bloccate, voglio:- ...scoprire se CSP è un motivo per 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 di js attualmente bloccati.


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

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

Passaggio 2: implementazione front-end

Abbiamo trasformato questo approfondimento nella prima bozza delle informazioni che volevamo rendere disponibili in DevTools tramite il protocollo CDP di Chrome DevTools:

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 di cui sopra codifica essenzialmente una struttura dati JSON. È scritto in un linguaggio semplice chiamato PDL (protocollo Data Language). La PDL viene utilizzata per due scopi. Innanzitutto, utilizziamo PDL per generare le definizioni TypeScript utilizzate dal front-end 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 ancora 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 avere stabilito quali informazioni volevamo rendere disponibili, abbiamo dovuto scoprire dove recuperare queste informazioni da Chromium.

Passaggio 3: rilevamento dei problemi

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

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 a come vengono gestiti i messaggi della console. Ciò significa che non segnaliamo subito i problemi al front-end, ma utilizziamo uno spazio di archiviazione che viene completato indipendentemente dal fatto che DevTools sia aperto o meno. Una volta aperto DevTools (o, in tal caso, qualsiasi altro client CDP) è possibile riprodurre di nuovo tutti i problemi registrati in precedenza dallo spazio di archiviazione.

Il lavoro di back-end si è concluso e ora dovevamo concentrarci su come individuare 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, ci affidiamo spesso alle informazioni del team che implementa una funzionalità (in questo caso si tratta del team CSP) e, ovviamente, del team DevRel, che progetta il modo in cui gli sviluppatori web devono affrontare un certo tipo di problema. Solitamente, il testo del problema viene sottoposto a qualche perfezionamento fino a quando non è completo.

In genere il team DevTools inizia con una bozza approssimativa 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 addetto alle funzionalità e DevRel rende la descrizione molto più chiara e precisa.

I problemi relativi a CSP sulla tua pagina possono essere rilevati anche nella scheda appositamente dedicata alle violazioni CSP.

Debug dei problemi relativi ai tipi attendibili

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

Stampa dalla console migliorata

Quando lavoriamo con oggetti attendibili, vorremmo visualizzare almeno la stessa quantità di informazioni della controparte non attendibile. Sfortunatamente, al momento quando visualizzi un oggetto attendibile non vengono visualizzate informazioni sull'oggetto con wrapping.

Il motivo è che il valore visualizzato nella console deriva dalla chiamata a .valueOf() sull'oggetto per impostazione predefinita. Tuttavia, nel caso del tipo attendibile, 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 effettuata nella versione V8, un simile approccio presenta importanti svantaggi. Esistono molti oggetti che richiedono una visualizzazione personalizzata, ma il cui tipo è lo stesso a livello di JS. Poiché V8 è un tipo di codice JS puro, non è in grado di distinguere i concetti corrispondenti a un'API web, come un tipo attendibile. Per questo motivo, V8 deve chiedere aiuto all'incorporamento (Blink) per distinguerli.

Quindi, spostare quella parte del codice su Blink o su qualsiasi incorporatore sembra una scelta logica. Oltre al problema esposto, ci sono molti altri vantaggi:

  • Ogni incorporatore 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. Di conseguenza, se usiamo .toString() per generare la descrizione, non c'è alcun rischio che .toString() venga ridefinito.

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

Attualmente, l'unico modo per eseguire il debug delle violazioni di TT è impostare i punti di interruzione nelle eccezioni JS. Poiché le violazioni delle tecniche di TT in modo forzato attivano un'eccezione, questa funzione può essere in qualche modo utile. Tuttavia, in scenari reali hai bisogno di un controllo più granulare sulle violazioni TT. In particolare, vorremmo interrompere solo le violazioni di TT (non altre eccezioni), interrompere anche la modalità di solo report e distinguere tra i diversi tipi di violazioni di TT.

DevTools supporta già un'ampia varietà di punti di interruzione, pertanto l'architettura è abbastanza estensibile. L'aggiunta di un nuovo tipo di punto di interruzione richiede modifiche nel backend (Blink), CDP e nel frontend. Dovremmo introdurre un nuovo comando CDP, che chiamiamo setBreakOnTTViolation. Questo comando verrà utilizzato dal frontend per indicare al backend il tipo di violazioni TT che dovrebbero interrompere. Il backend, in particolare InspectorDOMDebuggerAgent, fornirà un "probe" (probe), onTTViolation() che verrà chiamato ogni volta che si verifica una violazione di TTS. Quindi, 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.

Che cosa viene fatto e quali sono i passaggi successivi?

Dall'introduzione dei problemi descritti di seguito, la scheda Problemi ha subito alcune modifiche:

In futuro, prevediamo di utilizzare la scheda Problemi per individuare altri problemi e a lungo termine sarà possibile scaricare la console del flusso illeggibile dei messaggi di errore.

Scarica i canali in anteprima

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

Contattare il team di Chrome DevTools

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

  • Inviaci un suggerimento o un feedback tramite crbug.com.
  • Segnala un problema DevTools utilizzando Altre opzioni   Altre   > Guida > Segnala i problemi di DevTools in DevTools.
  • Tweet all'indirizzo @ChromeDevTools.
  • Lascia commenti sui video di YouTube o sui suggerimenti di DevTools in DevTools Video di YouTube.