Generatore CSP

Dacci l’indirizzo di una pagina reale. Leggiamo il suo HTML, elenchiamo tutti i posti da cui carica script, stili, immagini, font e frame, e scriviamo una policy che puoi provare in modalità report-only, dove non può rompere niente.

Scegli una pagina tipica, non solo la home page: una scheda prodotto, un articolo, il modulo di contatto. Ognuna può caricare da posti diversi.

Oppure prova github.com, wordpress.org, www.bbc.com

Una lista degli invitati per le tue pagine

Un browser fa tutto ciò che gli dice una pagina. Se l’HTML dice «esegui questo script da quel server», lo esegue. Diventa pericoloso il giorno in cui qualcun altro riesce ad aggiungere una riga alla tua pagina, tramite un campo commenti mai ripulito, un plugin compromesso o una pubblicità. Il browser non ha modo di distinguere la sua riga dalla tua.

Una Content-Security-Policy (CSP) è un header di risposta con cui dici al browser, in anticipo, da dove questa pagina può caricare le cose. Si legge come una lista degli invitati, con una riga per tipo di risorsa:

default-src 'self';
script-src 'self' https://cdn.example.com;
img-src 'self' data: https://images.example.net;
object-src 'none'

Ogni riga è una direttiva. 'self' indica l’origine stessa della pagina. Tutto ciò che non è in lista viene rifiutato, e il rifiuto viene registrato nella console del browser.

Come questa pagina crea la bozza

Il nostro server scarica l’indirizzo una volta e analizza l’HTML come farebbe un browser, senza eseguire nulla. Ogni indirizzo trovato viene ridotto alla sua origine (schema e host, niente percorso) e archiviato:

DirettivaLetta da
script-src<script src>, preload dei moduli e indirizzi di script citati negli snippet di caricamento inline
style-srclink ai fogli di stile e regole @import
img-src, font-srctag immagine, srcset, icone, poster, preload e url() nel CSS inline e nei primi quattro fogli di stile dell’origine del sito
frame-src, media-src, object-src, manifest-srcframe, audio e video, plugin, link al manifest
form-action, base-uridestinazioni dei moduli e tag <base>
connect-srcsolo i suggerimenti preconnect e gli endpoint documentati di alcuni servizi trovati nella pagina (Google Analytics, Google Fonts, Cloudflare Web Analytics)

La bozza parte da default-src 'self', aggiunge una riga per direttiva e chiude le porte che non hanno ripiego: object-src 'none', base-uri 'self', frame-ancestors 'self', più upgrade-insecure-requests sulle pagine HTTPS. Se la pagina invia già una policy, in un header o in un meta tag, te la mostriamo e la confrontiamo con ciò che la pagina carica.

La parte difficile: il codice inline

Il codice iniettato è quasi sempre inline, come blocco <script> o attributo onclick scritto nella pagina. Una policy che valga qualcosa vieta quindi il codice inline. Il problema è che la maggior parte dei siti ne ha parecchio di suo. Lo strumento conta blocchi di script, attributi di gestione degli eventi, link javascript:, blocchi di stile e attributi style=, poi ti dà due bozze.

  • La bozza rigorosa non ha 'unsafe-inline'. È lì che vuoi arrivare, e romperebbe il codice inline contato sopra.
  • La bozza di transizione aggiunge 'unsafe-inline' dove la pagina ne ha bisogno. Limita ancora i siti da cui si può caricare, ma non ferma più gli script inline iniettati, ed è per questo che è segnata come debole.

Puoi passare dall’una all’altra in tre modi. Sposta il codice in file, fai marcare a ogni tag dal server un nonce diverso per ogni risposta, oppure elenca nella policy l’hash SHA-256 di ogni blocco. Lo strumento calcola questi hash per i blocchi di script trovati. Servono solo per i blocchi il cui testo non cambia mai.

Prima report-only, sempre

Invia la bozza come Content-Security-Policy-Report-Only. Il browser non blocca niente e registra ciò che avrebbe bloccato. Naviga nel sito con la console aperta, aggiungi ciò che manca legittimamente e ripeti finché il registro tace. Poi rinomina l’header in Content-Security-Policy. Ricevi snippet per Apache, nginx e un meta tag. La forma meta non supporta né il report-only né frame-ancestors.

La bozza viene da una sola pagina, letta una volta, senza eseguire nulla. Non vede le richieste fatte dagli script dopo il caricamento (beacon di analytics, widget di chat, frame di pagamento, immagini caricate in differita), ciò che ricevono i visitatori connessi, né le altre pagine del sito. Mettiti in conto di aggiungere fonti. Per un voto agli header che una pagina invia oggi, usa il voto degli header di sicurezza.

Domande frequenti

Una Content-Security-Policy romperà il mio sito?

Una policy applicata blocca tutto ciò che non elenca, quindi una sbagliata lo romperà. Una policy report-only non può rompere niente, perché si limita a registrare. Parti da lì e passa all’applicazione quando la console non mostra più violazioni sulle pagine principali.

Una policy con unsafe-inline serve a qualcosa?

In parte. Limita comunque dove possono andare script, frame e invii di moduli, blocca i plugin e impedisce il dirottamento tramite tag <base>. Non ferma un attaccante che riesce a scrivere un blocco di script nella pagina, ed è proprio quello il motivo principale per avere una policy. Usala come tappa intermedia.

Che differenza c’è tra un nonce e un hash?

Un nonce è un valore casuale che il server genera per ogni risposta e ripete su ogni tag script di cui si fida. Un hash è l’impronta di un blocco di codice specifico, elencata nella policy. I nonce vanno bene per pagine generate a ogni richiesta. Gli hash vanno bene per pochi snippet statici su pagine che possono finire in cache.

Perché i percorsi sono esclusi dalla policy generata?

La CSP ammette percorsi come https://cdn.example.com/lib/, ma vengono ignorati dopo un redirect e si rompono appena un file viene spostato. La maggior parte delle policy in uso elenca le origini. Se un’origine ospita file di molti soggetti diversi, come una CDN pubblica, blocca anche i file esatti con gli hash di integrità.

Posso impostare una CSP su WordPress o un altro CMS?

Sì, tramite la configurazione del server web o un plugin di sicurezza che invia gli header. Tema e plugin porteranno con sé una lunga lista di script e stili inline, quindi comincia con l’header report-only e la bozza di transizione, poi riduci il codice inline un plugin alla volta.

Dove vedo cosa blocca la policy?

Nella scheda Console degli strumenti per sviluppatori del browser. Ogni violazione indica la direttiva e l’indirizzo bloccato. Per raccoglierle dai visitatori, aggiungi una direttiva report-uri o report-to che punti a un raccoglitore.