Content Security Policy (CSP)

Indice dei contenuti

    Content Security Policy (CSP) è un meccanismo di sicurezza implementato nei browser moderni che consente al server di specificare, tramite un HTTP header, quali origini sono autorizzate a fornire risorse (script, stili, immagini, font, frame) alla pagina corrente. È la principale difesa di seconda linea contro gli attacchi Cross-Site Scripting (XSS): anche se un attaccante riesce a iniettare codice nella pagina, il browser lo rifiuta se l’origine non è nella lista bianca.

    CSP non elimina la necessità di sanificare l’input — rimane una misura di defense in depth.

    Come funziona

    Il server invia l’header:

    Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.esempio.it; img-src *

    Il browser analizza la policy e, per ogni risorsa che la pagina tenta di caricare, verifica se l’origine corrisponde alla direttiva applicabile. Se non corrisponde, la risorsa viene bloccata e l’evento viene registrato nella console (e opzionalmente inviato a un endpoint di reporting).

    In alternativa all’header HTTP, CSP può essere dichiarata tramite un meta tag HTML, ma questa modalità ha limitazioni (non copre form-action, frame-ancestors, e altri).

    Direttive principali

    DirettivaControlla
    default-srcFallback per tutte le risorse non coperte da una direttiva specifica
    script-srcScript JavaScript
    style-srcFogli di stile CSS
    img-srcImmagini
    font-srcFont
    connect-srcRichieste XHR, Fetch, WebSocket
    frame-srcContenuto caricato in <iframe>
    frame-ancestorsChi può incorporare questa pagina in un frame (difesa anti-clickjacking)
    form-actionA quali URL possono essere inviati i form
    base-uriValore dell’elemento <base>
    object-srcPlugin (<object>, <embed>, <applet>)
    upgrade-insecure-requestsForza upgrade automatico da HTTP a HTTPS

    Valori delle sorgenti

    'self'           → stessa origine (schema + host + porta)
    'none'           → nessuna risorsa consentita
    'unsafe-inline'  → script/stili inline (sconsigliato: annulla protezione XSS)
    'unsafe-eval'    → eval() e funzioni dinamiche (sconsigliato)
    https:           → qualsiasi origine HTTPS
    https://cdn.esempio.it → origine specifica
    'nonce-<base64>' → script inline con nonce monouso
    'sha256-<hash>'  → script inline con hash SHA-256 specifico

    Nonce e hash — la soluzione moderna

    L’uso di 'unsafe-inline' svuota la protezione CSP perché consente qualsiasi script inline, inclusi quelli iniettati dall’attaccante. La soluzione corretta per gli script inline legittimi è:

    Nonce: il server genera un valore casuale monouso per ogni risposta e lo include sia nella policy che nell’attributo nonce degli script legittimi:

    <!-- Header -->
    Content-Security-Policy: script-src 'nonce-r4nd0m1234'
    
    <!-- HTML -->
    <script nonce="r4nd0m1234">
      // script legittimo
    </script>

    Un attaccante che inietta <script> senza conoscere il nonce viene bloccato.

    Hash: alternativa al nonce per script con contenuto fisso — si include l’hash SHA-256 del testo dello script nella policy.

    Modalità report-only

    Durante il deployment, CSP può essere testata senza bloccare risorse usando l’header:

    Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report

    Il browser invia un report JSON all’endpoint /csp-report per ogni violazione, ma non blocca nulla. Permette di affinare la policy prima di metterla in produzione.

    Policy comune di partenza

    Una policy ragionevole per la maggior parte delle applicazioni web:

    Content-Security-Policy:
      default-src 'none';
      script-src 'self' 'nonce-{random}';
      style-src 'self' 'unsafe-inline';
      img-src 'self' data: https:;
      font-src 'self';
      connect-src 'self';
      frame-ancestors 'none';
      base-uri 'self';
      form-action 'self';
      upgrade-insecure-requests;

    default-src 'none' è il punto di partenza più restrittivo: tutto è vietato finché non esplicitamente consentito.

    Errori comuni

    • 'unsafe-inline' globale: neutralizza completamente la protezione XSS di CSP.
    • 'unsafe-eval': consente eval(), setTimeout(string), new Function() — vettori di XSS.
    • Wildcard eccessivi: script-src * equivale a nessun controllo.
    • Dimenticare object-src 'none': i plugin legacy sono vettori di bypass.
    • CSP solo via meta tag: non copre frame-ancestorsform-action.
    • Nonce statico: il nonce deve essere rigenerato a ogni risposta, non hardcoded.

    Relazione con altri meccanismi

    Ultimo aggiornamento: