Una guida completa per migliorare la sicurezza frontend utilizzando Content Security Policy (CSP) e Cross-Origin Resource Sharing (CORS), proteggendo le tue applicazioni web dalle minacce moderne.
Rafforzamento della Sicurezza Frontend: Content Security Policy e CORS
Nel panorama digitale interconnesso di oggi, la sicurezza frontend è di fondamentale importanza. Le applicazioni web sono sempre più bersaglio di attacchi sofisticati, rendendo essenziali misure di sicurezza robuste. Due componenti critici di un'architettura frontend sicura sono la Content Security Policy (CSP) e il Cross-Origin Resource Sharing (CORS). Questa guida completa fornisce uno sguardo approfondito a queste tecnologie, offrendo esempi pratici e spunti attuabili per aiutarti a fortificare le tue applicazioni web contro le minacce moderne.
Cos'è la Content Security Policy (CSP)?
La Content Security Policy (CSP) è un ulteriore livello di sicurezza che aiuta a rilevare e mitigare alcuni tipi di attacchi, tra cui Cross-Site Scripting (XSS) e attacchi di iniezione di dati. La CSP viene implementata tramite l'invio da parte del server web di un header di risposta HTTP Content-Security-Policy al browser. Questo header definisce una whitelist di fonti da cui il browser è autorizzato a caricare risorse. Limitando le fonti di contenuto che un browser può caricare, la CSP rende significativamente più difficile per gli aggressori iniettare codice dannoso nel tuo sito web.
Come Funziona la CSP
La CSP funziona istruendo il browser a caricare risorse (ad es. script, fogli di stile, immagini, font) solo da fonti approvate. Queste fonti sono specificate nell'header CSP tramite direttive. Se un browser tenta di caricare una risorsa da una fonte non esplicitamente consentita, bloccherà la richiesta e segnalerà una violazione.
Direttive CSP: Una Panoramica Completa
Le direttive CSP controllano i tipi di risorse che possono essere caricate da fonti specifiche. Ecco una ripartizione di alcune delle direttive più importanti:
- default-src: Specifica la fonte predefinita per tutti i tipi di contenuto. È una direttiva di fallback che si applica quando altre direttive più specifiche non sono presenti.
- script-src: Specifica le fonti da cui possono essere caricati gli script. Questo è cruciale per prevenire attacchi XSS.
- style-src: Specifica le fonti da cui possono essere caricati i fogli di stile.
- img-src: Specifica le fonti da cui possono essere caricate le immagini.
- font-src: Specifica le fonti da cui possono essere caricati i font.
- media-src: Specifica le fonti da cui possono essere caricati audio e video.
- object-src: Specifica le fonti da cui possono essere caricati i plugin (es. Flash). Spesso viene impostato su 'none' per disabilitare completamente i plugin a causa dei loro rischi di sicurezza intrinseci.
- frame-src: Specifica le fonti da cui possono essere caricati i frame (es. <iframe>).
- connect-src: Specifica gli URL a cui lo user agent può connettersi utilizzando interfacce di script come XMLHttpRequest, WebSocket ed EventSource.
- base-uri: Specifica gli URL che possono essere utilizzati nell'elemento <base> di un documento.
- form-action: Specifica gli URL a cui possono essere inviati i moduli.
- upgrade-insecure-requests: Istruisce lo user agent ad aggiornare automaticamente le richieste non sicure (HTTP) a richieste sicure (HTTPS).
- report-uri: Specifica un URL a cui il browser dovrebbe inviare i report sulle violazioni della CSP. Questa direttiva è deprecata a favore di `report-to`.
- report-to: Specifica il nome di un gruppo di reporting definito nell'header `Report-To`, a cui il browser dovrebbe inviare i report sulle violazioni della CSP.
Parole Chiave della Lista di Origini CSP
All'interno delle direttive CSP, è possibile utilizzare parole chiave della lista di origini per definire le fonti consentite. Ecco alcune parole chiave comuni:
- 'self': Consente risorse dalla stessa origine (schema e host) del documento.
- 'none': Non consente risorse da nessuna fonte.
- 'unsafe-inline': Consente l'uso di script e stili inline (ad es. tag <script> e attributi di stile). Usare con estrema cautela poiché indebolisce significativamente la protezione CSP contro XSS.
- 'unsafe-eval': Consente l'uso di funzioni di valutazione dinamica del codice come
eval()eFunction(). Usare con estrema cautela poiché introduce significativi rischi per la sicurezza. - 'unsafe-hashes': Consente specifici gestori di eventi inline o tag <style> che corrispondono a un hash specificato. Richiede il supporto del browser. Usare con cautela.
- 'strict-dynamic': Specifica che la fiducia data esplicitamente a uno script presente nel markup, accompagnandolo con un nonce o un hash, deve essere propagata a tutti gli script caricati da quello script radice.
- data: Consente data: URI (ad es. immagini inline codificate in base64). Usare con cautela.
- https:: Consente il caricamento di risorse tramite HTTPS da qualsiasi dominio.
- [hostname]: Consente risorse da un dominio specifico (ad es. example.com). È possibile specificare anche un numero di porta (ad es. example.com:8080).
- [scheme]://[hostname]:[port]: Un URI completo, che consente risorse dallo schema, host e porta specificati.
Esempi Pratici di CSP
Diamo un'occhiata ad alcuni esempi pratici di header CSP:
Esempio 1: CSP di Base con 'self'
Questa policy consente risorse solo dalla stessa origine:
Content-Security-Policy: default-src 'self'
Esempio 2: Consentire Script da un Dominio Specifico
Questa policy consente script dal proprio dominio e da un CDN attendibile:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com
Esempio 3: Disabilitare Script e Stili Inline
Questa policy non consente script e stili inline, che è una forte difesa contro XSS:
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'
Importante: Disabilitare gli script inline richiede di refattorizzare il tuo HTML per spostare gli script inline in file esterni.
Esempio 4: Usare Nonce per Script Inline
Se devi usare script inline, usa i nonce (token crittograficamente casuali e monouso) per inserire in whitelist specifici blocchi di script inline. Questo è più sicuro di 'unsafe-inline'. Il server deve generare un nonce unico per ogni richiesta e includerlo sia nell'header CSP che nel tag <script>.
Content-Security-Policy: default-src 'self'; script-src 'nonce-r4nd0mN0nc3'; style-src 'self'
<script nonce="r4nd0mN0nc3"> console.log('Script inline'); </script>
Nota: Ricorda di generare un nuovo nonce per ogni richiesta. Non riutilizzare i nonce!
Esempio 5: Usare Hash per Stili Inline
Similmente ai nonce, gli hash possono essere usati per inserire in whitelist specifici blocchi <style> inline. Questo si fa generando un hash SHA256, SHA384 o SHA512 del contenuto dello stile.
Content-Security-Policy: default-src 'self'; style-src 'sha256-HASHEDSTYLES'
<style sha256="HASHEDSTYLES"> body { background-color: #f0f0f0; } </style>
Nota: Gli hash sono meno flessibili dei nonce poiché qualsiasi modifica al contenuto dello stile invaliderà l'hash.
Esempio 6: Segnalare Violazioni CSP
Per monitorare le violazioni della CSP, usa la direttiva report-uri o report-to:
Content-Security-Policy: default-src 'self'; report-to csp-endpoint;
Dovrai anche configurare l'header Report-To. L'header Report-To definisce uno o più gruppi di reporting, che specificano dove e come i report dovrebbero essere inviati.
Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://example.com/csp-report"}]}
Test e Implementazione della CSP
L'implementazione della CSP richiede un'attenta pianificazione e test. Inizia con una policy restrittiva e allentala gradualmente secondo necessità. Usa l'header Content-Security-Policy-Report-Only per testare la tua policy senza bloccare le risorse. Questo header segnala le violazioni senza applicare la policy, permettendoti di identificare e risolvere i problemi prima di implementare la policy in produzione.
Content-Security-Policy-Report-Only: default-src 'self'; report-to csp-endpoint;
Analizza i report generati dal browser per identificare eventuali violazioni e adegua la tua policy di conseguenza. Una volta che sei sicuro che la tua policy funzioni correttamente, implementala utilizzando l'header Content-Security-Policy.
Best Practice per la CSP
- Inizia con un default-src: Definisci sempre un
default-srcper stabilire una policy di base. - Sii specifico: Usa direttive e parole chiave della lista di origini specifiche per limitare il campo d'azione della tua policy.
- Evita 'unsafe-inline' e 'unsafe-eval': Queste parole chiave indeboliscono significativamente la CSP e dovrebbero essere evitate quando possibile.
- Usa nonce o hash per script e stili inline: Se devi usare script o stili inline, usa nonce o hash per inserire in whitelist blocchi di codice specifici.
- Monitora le violazioni della CSP: Usa la direttiva
report-urioreport-toper monitorare le violazioni della CSP e adeguare la tua policy di conseguenza. - Testa a fondo: Usa l'header
Content-Security-Policy-Report-Onlyper testare la tua policy prima di implementarla in produzione. - Itera e perfeziona: La CSP non è una configurazione una tantum. Monitora e perfeziona continuamente la tua policy per adattarla ai cambiamenti della tua applicazione e al panorama delle minacce.
Cos'è il Cross-Origin Resource Sharing (CORS)?
Il Cross-Origin Resource Sharing (CORS) è un meccanismo che consente alle pagine web di un'origine (dominio) di accedere a risorse di un'origine diversa. Per impostazione predefinita, i browser applicano una Same-Origin Policy, che impedisce agli script di effettuare richieste a un'origine diversa da quella da cui lo script è stato originato. Il CORS fornisce un modo per allentare selettivamente questa restrizione, consentendo richieste cross-origin legittime e proteggendo al contempo da attacchi dannosi.
Comprendere la Same-Origin Policy
La Same-Origin Policy è un meccanismo di sicurezza fondamentale che impedisce a uno script dannoso di un sito web di accedere a dati sensibili su un altro sito web. Un'origine è definita dallo schema (protocollo), host (dominio) e porta. Due URL hanno la stessa origine se e solo se hanno lo stesso schema, host e porta.
Per esempio:
https://www.example.com/app1/index.htmlehttps://www.example.com/app2/index.htmlhanno la stessa origine.https://www.example.com/index.htmlehttp://www.example.com/index.htmlhanno origini diverse (schema diverso).https://www.example.com/index.htmlehttps://sub.example.com/index.htmlhanno origini diverse (host diverso).https://www.example.com:8080/index.htmlehttps://www.example.com:80/index.htmlhanno origini diverse (porta diversa).
Come Funziona il CORS
Quando una pagina web effettua una richiesta cross-origin, il browser invia prima una richiesta "preflight" al server. La richiesta preflight utilizza il metodo HTTP OPTIONS e include header che indicano il metodo HTTP e gli header che la richiesta effettiva utilizzerà. Il server risponde quindi con header che indicano se la richiesta cross-origin è consentita.
Se il server consente la richiesta, include l'header Access-Control-Allow-Origin nella risposta. Questo header specifica le origini che sono autorizzate ad accedere alla risorsa. Il browser procede quindi con la richiesta effettiva. Se il server non consente la richiesta, non include l'header Access-Control-Allow-Origin e il browser blocca la richiesta.
Header CORS: Uno Sguardo Dettagliato
Il CORS si basa su header HTTP per comunicare tra il browser e il server. Ecco gli header CORS chiave:
- Access-Control-Allow-Origin: Specifica le origini autorizzate ad accedere alla risorsa. Questo header può contenere un'origine specifica (ad es.
https://www.example.com), un carattere jolly (*), onull. L'uso di*consente richieste da qualsiasi origine, il che generalmente non è raccomandato per motivi di sicurezza. L'uso di `null` è appropriato solo per "risposte opache" come quando la risorsa viene recuperata utilizzando il protocollo `file://` o un data URI. - Access-Control-Allow-Methods: Specifica i metodi HTTP consentiti per la richiesta cross-origin (ad es.
GET, POST, PUT, DELETE). - Access-Control-Allow-Headers: Specifica gli header HTTP consentiti nella richiesta cross-origin. Questo è importante per la gestione di header personalizzati.
- Access-Control-Allow-Credentials: Indica se il browser deve includere le credenziali (ad es. cookie, header di autorizzazione) nella richiesta cross-origin. Questo header deve essere impostato su
trueper consentire le credenziali. - Access-Control-Expose-Headers: Specifica quali header possono essere esposti al client. Per impostazione predefinita, è esposto solo un set limitato di header.
- Access-Control-Max-Age: Specifica la quantità massima di tempo (in secondi) per cui il browser può memorizzare nella cache la richiesta preflight.
- Origin: Questo è un header di richiesta inviato dal browser per indicare l'origine della richiesta.
- Vary: Un header HTTP generale, ma importante per il CORS. Quando
Access-Control-Allow-Originè generato dinamicamente, l'headerVary: Origindovrebbe essere incluso nella risposta per istruire i meccanismi di caching che la risposta varia in base all'header di richiestaOrigin.
Esempi Pratici di CORS
Diamo un'occhiata ad alcuni esempi pratici di configurazioni CORS:
Esempio 1: Consentire Richieste da un'Origine Specifica
Questa configurazione consente richieste solo da https://www.example.com:
Access-Control-Allow-Origin: https://www.example.com
Esempio 2: Consentire Richieste da Qualsiasi Origine (Sconsigliato)
Questa configurazione consente richieste da qualsiasi origine. Usare con cautela poiché può introdurre rischi per la sicurezza:
Access-Control-Allow-Origin: *
Esempio 3: Consentire Metodi e Header Specifici
Questa configurazione consente i metodi GET, POST e PUT, e gli header Content-Type e Authorization:
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Esempio 4: Consentire le Credenziali
Per consentire le credenziali (ad es. cookie), è necessario impostare Access-Control-Allow-Credentials su true e specificare un'origine specifica (non è possibile utilizzare * quando si consentono le credenziali):
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Credentials: true
È inoltre necessario impostare credentials: 'include' nella tua richiesta JavaScript fetch/XMLHttpRequest.
fetch('https://api.example.com/data', {
credentials: 'include'
})
Richieste Preflight CORS
Per alcuni tipi di richieste cross-origin (ad es. richieste con header personalizzati o metodi diversi da GET, HEAD o POST con Content-Type di application/x-www-form-urlencoded, multipart/form-data o text/plain), il browser invia una richiesta preflight utilizzando il metodo OPTIONS. Il server deve rispondere alla richiesta preflight con gli header CORS appropriati per indicare se la richiesta effettiva è consentita.
Ecco un esempio di una richiesta e risposta preflight:
Richiesta Preflight (OPTIONS):
OPTIONS /data HTTP/1.1
Origin: https://www.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization
Risposta Preflight (200 OK):
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
L'header Access-Control-Max-Age specifica per quanto tempo il browser può memorizzare nella cache la risposta preflight, riducendo il numero di richieste preflight.
CORS e JSONP
JSON with Padding (JSONP) è una tecnica più vecchia per aggirare la Same-Origin Policy. Tuttavia, JSONP presenta notevoli rischi per la sicurezza e dovrebbe essere evitato a favore del CORS. JSONP si basa sull'iniezione di tag <script> nella pagina, che possono eseguire codice arbitrario. Il CORS fornisce un modo più sicuro e flessibile per gestire le richieste cross-origin.
Best Practice per il CORS
- Evita di usare *: Evita di usare il carattere jolly (*) nell'header
Access-Control-Allow-Origin, poiché consente richieste da qualsiasi origine. Specifica invece le origini specifiche autorizzate ad accedere alla risorsa. - Sii specifico con metodi e header: Specifica i metodi HTTP e gli header esatti consentiti negli header
Access-Control-Allow-MethodseAccess-Control-Allow-Headers. - Usa Access-Control-Allow-Credentials con cautela: Abilita
Access-Control-Allow-Credentialssolo se devi consentire le credenziali (ad es. cookie) nelle richieste cross-origin. Sii consapevole delle implicazioni di sicurezza nel consentire le credenziali. - Proteggi le tue richieste preflight: Assicurati che il tuo server gestisca correttamente le richieste preflight e restituisca gli header CORS corretti.
- Usa HTTPS: Usa sempre HTTPS sia per l'origine che per le risorse a cui accedi cross-origin. Questo aiuta a proteggere dagli attacchi man-in-the-middle.
- Vary: Origin: Se stai generando dinamicamente l'header `Access-Control-Allow-Origin`, includi sempre l'header `Vary: Origin` per prevenire problemi di caching.
CSP e CORS in Pratica: Un Approccio Combinato
Mentre sia CSP che CORS affrontano problemi di sicurezza, operano a livelli diversi e forniscono una protezione complementare. La CSP si concentra sull'impedire al browser di caricare contenuti dannosi, mentre il CORS si concentra sul controllo di quali origini possono accedere alle risorse sul tuo server.
Combinando CSP e CORS, puoi creare una postura di sicurezza più robusta per le tue applicazioni web. Ad esempio, puoi usare la CSP per limitare le fonti da cui possono essere caricati gli script e il CORS per controllare quali origini possono accedere ai tuoi endpoint API.
Esempio: Mettere in Sicurezza un'API con CSP e CORS
Supponiamo di avere un'API ospitata su https://api.example.com che vuoi rendere accessibile solo da https://www.example.com. Puoi configurare il tuo server per restituire i seguenti header:
Header di Risposta dell'API (https://api.example.com):
Access-Control-Allow-Origin: https://www.example.com
Content-Type: application/json
E puoi configurare il tuo sito web (https://www.example.com) per utilizzare il seguente header CSP:
Header CSP del Sito Web (https://www.example.com):
Content-Security-Policy: default-src 'self'; script-src 'self'; connect-src 'self' https://api.example.com;
Questa policy CSP consente al sito web di caricare script e connettersi all'API, ma gli impedisce di caricare script o connettersi ad altri domini.
Conclusione
Content Security Policy (CSP) e Cross-Origin Resource Sharing (CORS) sono strumenti essenziali per rafforzare la sicurezza delle tue applicazioni frontend. Configurando attentamente CSP e CORS, puoi ridurre significativamente il rischio di attacchi XSS, attacchi di iniezione di dati e altre vulnerabilità di sicurezza. Ricorda di iniziare con una policy restrittiva, testare a fondo e monitorare e perfezionare continuamente la tua configurazione per adattarla ai cambiamenti della tua applicazione e al panorama delle minacce in evoluzione. Dando la priorità alla sicurezza frontend, puoi proteggere i tuoi utenti e garantire l'integrità delle tue applicazioni web nel mondo digitale sempre più complesso di oggi.