HEADER PER HEADER

Verifica degli header di sicurezza: come trovare e correggere quelli HTTP mancanti

Gli header di sicurezza sono istruzioni che il server invia insieme alle risposte: quali risorse una pagina può caricare, se il browser deve insistere su HTTPS, chi può inserire la pagina in un frame. Ecco come leggerli da soli, che cosa fa ciascuno, valori di partenza sicuri e un ordine di rilascio che permette di testare ogni modifica prima di applicarla.

Illustrazione concettuale: un fascio di luce verde menta attraversa cinque vetri decorati verso un arco color avorio, mentre una lente di rame ispeziona uno dei vetri.
Illustrazione concettuale

Ogni risposta del tuo sito porta con sé header che il visitatore non vede mai. Alcuni sono istruzioni di sicurezza per il browser: carica gli script solo da questi luoghi, usa HTTPS per questo host, non lasciare che altri siti inseriscano questa pagina in un frame, tieni questo cookie lontano da JavaScript. Quando mancano, il browser ripiega sui suoi default più permissivi. Quando sono sbagliati, accesso o checkout possono smettere di funzionare.

Questa guida spiega come leggere gli header che il tuo sito invia davvero, che cosa fa ciascuno e da quali valori conviene partire. Include una configurazione di base per nginx e per host statici come Cloudflare Pages e Netlify, e gli errori che lasciano alcune risposte senza header. Tutti gli esempi usano example.com.

Ambito di questa guida

Lo snapshot gratuito legge gli header di una sola risposta: la home page dell’origine inserita, dopo al massimo cinque redirect. Verifica soprattutto la presenza di ogni header, non l’adeguatezza dei valori. Non è un pentest.

1. Controlla gli header da solo: DevTools e curl

In Chrome o Edge apri DevTools, seleziona il pannello Network e ricarica la pagina. Fai clic sulla prima richiesta (il documento HTML), apri la scheda Headers e scorri fino a Response Headers. Attiva Preserve log per conservare le richieste tra caricamenti e redirect e Disable cache per ottenere una risposta nuova anziché una in cache (riferimento Chrome DevTools sulla rete). Il Network Monitor di Firefox funziona allo stesso modo.

Da terminale, curl mostra esattamente ciò che invia il server:

curl -sS -D - -o /dev/null https://example.com/

Aggiungi -L per seguire i redirect e vedere gli header di ogni passaggio. Su Windows usa curl.exe e -o NUL. curl -I è più breve, ma invia una richiesta HEAD anziché GET, e alcune applicazioni gestiscono HEAD con un percorso di codice diverso: conferma quindi ciò che trovi con una GET.

Ripeti il controllo per l’indirizzo http:// (dovrebbe rispondere con un redirect 301 o 308 verso HTTPS), per l’altro nome host (www o dominio senza prefisso), per una pagina inesistente, una pagina di accesso, una risposta API e un file statico. Applicazione, web server e CDN spesso impostano header diversi su ciascuna di queste risposte, e conta solo ciò che arriva al browser.

2. Che cosa fa ogni header e da quale valore partire

HeaderChe cosa faValore di partenza sicuro
Content-Security-PolicyLimita da dove possono essere caricati script, stili, frame e altre risorseUna policy in bozza, inviata prima come Content-Security-Policy-Report-Only
CSP frame-ancestorsDecide quali siti possono incorporare la pagina in un frame (difesa dal clickjacking)frame-ancestors 'self' oppure 'none'
X-Frame-OptionsControllo storico dei frame, mantenuto come ripiego per i browser più vecchiSAMEORIGIN o DENY, coerente con frame-ancestors
Strict-Transport-SecurityChiede al browser di usare solo HTTPS per questo host per max-age secondimax-age=300, aumentato per gradi
X-Content-Type-OptionsImpedisce di indovinare il tipo MIME; blocca script e fogli di stile serviti con il tipo sbagliatonosniff
Referrer-PolicyControlla quanto dell’URL della pagina viene inviato ad altri siti nell’header Refererstrict-origin-when-cross-origin
Permissions-PolicyDisattiva funzioni del browser, come la fotocamera, per la pagina e i suoi framecamera=(), microphone=(), geolocation=()
Cross-Origin-Opener-PolicyIsola la tua finestra dai pop-up di altre origini e dalla pagina che l’ha apertasame-origin, oppure same-origin-allow-popups per pop-up OAuth o di pagamento
Attributi di Set-CookieLimitano come viaggiano i cookie di sessione e chi può leggerliSecure; HttpOnly; SameSite=Lax
X-XSS-ProtectionControllava un filtro nei vecchi browser; oggi è deprecatoRimuovilo, oppure invia 0

Con nosniff il browser si fida del Content-Type dichiarato e blocca script e fogli di stile che arrivano con quello sbagliato, quindi controlla quei tipi prima di attivarlo. Senza un header Referrer-Policy, i browser attuali usano già strict-origin-when-cross-origin; OWASP consiglia comunque di inviarlo in modo esplicito per i browser più vecchi, e no-referrer è più restrittivo se nulla di ciò che usi richiede il referrer. In Permissions-Policy, () disattiva una funzione nella pagina e in ogni frame al suo interno; consentila solo per l’origine del widget che ne ha bisogno. COOP same-origin aiuta contro gli attacchi di leak cross-origin (XS-Leaks) ma può rompere pop-up di accesso o pagamento serviti da un’altra origine.

3. Content-Security-Policy e frame-ancestors

La CSP dice al browser da dove una pagina può caricare script, stili, immagini, frame e connessioni. Limita ciò che può fare uno script iniettato; non sostituisce l’escaping e la validazione dell’input. La guida CSP di MDN raccomanda una strict CSP basata su un nonce nuovo per ogni risposta, o su hash, anziché su un lungo elenco di host consentiti. 'unsafe-inline' vanifica gran parte dello scopo, e il browser lo ignora in qualsiasi direttiva che contenga anche un nonce o un hash. Ciò che rende difficile una policy rigorosa è di solito il codice di terze parti che carica altri script, come tag manager e widget di chat: annota il motivo di ogni eccezione che aggiungi.

default-src è il ripiego per le direttive di fetch come script-src, ma non per frame-ancestors: una policy default-src 'none' lascia comunque a qualsiasi sito la possibilità di inserire la pagina in un frame. Imposta frame-ancestors 'self' in modo esplicito, oppure 'none', simile a X-Frame-Options: DENY (MDN). L’OWASP HTTP Headers Cheat Sheet afferma che frame-ancestors rende obsoleto X-Frame-Options nei browser che lo supportano, mentre X-Frame-Options copre ancora quelli più vecchi; se li invii entrambi, fai in modo che consentano lo stesso inserimento nei frame. Due trappole: frame-ancestors, una policy report-only e X-Frame-Options non hanno effetto in un tag <meta>, e X-Frame-Options: ALLOW-FROM fa ignorare l’intero header ai browser moderni.

Una prima bozza per un sito senza script di terze parti è la policy raccomandata dall’OWASP Secure Headers Project:

default-src 'self'; form-action 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'; upgrade-insecure-requests

Blocca script e stili inline e tutto ciò che viene caricato da altri host, quindi aspettati molte segnalazioni all’inizio; per questo parte come Report-Only (sezione 8). Prendi solo la riga della CSP: l’insieme completo del progetto contiene anche valori come Cache-Control: no-store e Clear-Site-Data, che disattiverebbero la cache e cancellerebbero cookie e dati salvati del visitatore a ogni risposta. Sulle risposte API JSON, che il browser non renderizza, la CSP serve a poco.

4. HSTS: aumenta max-age per gradi e pensaci bene prima del preload

Strict-Transport-Security dice al browser di usare solo HTTPS per l’host e di convertire automaticamente le successive richieste http://. I browser ignorano l’header quando arriva su HTTP semplice, quindi invialo sulle risposte HTTPS, non sul redirect da HTTP a HTTPS. Da solo non può proteggere la primissima connessione di un visitatore.

Metti in conto il costo: su un host con HSTS i visitatori non possono ignorare gli errori di certificato, quindi un certificato scaduto esclude chi torna sul sito. I certificati TLS pubblici emessi dal 15 marzo 2026 possono avere una validità massima di 200 giorni (CA/Browser Forum), e Let’s Encrypt non invia più email di promemoria di scadenza: prepara prima il rinnovo automatico e un tuo monitoraggio delle scadenze. La guida a SSL/TLS e header di sicurezza tratta il lato certificati.

Aumenta max-age (in secondi) per gradi, come raccomanda hstspreload.org, e controlla che nulla si rompa a ogni passaggio: 300 (5 minuti), 604800 (1 settimana), 2592000 (1 mese), poi 31536000 (1 anno) o 63072000 (2 anni, il valore usato da OWASP). max-age=0 rimuove la policy, ma solo se inviato su HTTPS e solo per i visitatori che tornano e lo ricevono. Aggiungi includeSubDomains quando ogni sottodominio funziona su HTTPS, e fai inviare a ciascun sottodominio il proprio header.

Il preload incorpora il tuo dominio nei browser, così anche la prima visita usa HTTPS. Il sito di invio, hstspreload.org, ora raccomanda HSTS ma non il preload: Chrome e Safari convertono già in HTTPS le navigazioni HTTP, quindi il preload aggiunge poco, e una rimozione dall’elenco impiega mesi per raggiungere gli utenti. L’OWASP HTTP Headers Cheat Sheet include ancora preload nell’header di esempio, mentre il valore raccomandato dall’OWASP Secure Headers Project lo omette. Non aggiungerlo per impostazione predefinita né copiarlo da un modello.

5. Attributi dei cookie: Secure, HttpOnly e SameSite

Set-Cookie: __Host-session=…; Path=/; Secure; HttpOnly; SameSite=Lax
  • Secure fa sì che il browser invii il cookie solo su HTTPS (localhost escluso). Non nasconde il cookie a JavaScript.
  • HttpOnly impedisce agli script della pagina di leggere il cookie (per esempio tramite document.cookie), ma il browser lo invia comunque con le richieste corrispondenti: limita quindi il furto di cookie tramite XSS senza prevenire l’XSS stesso.
  • SameSite decide se il cookie accompagna le richieste cross-site. Con Strict non succede mai. Con Lax accompagna anche le navigazioni GET di primo livello da un altro sito, per esempio un visitatore che segue un link verso il tuo. Con None accade sempre, e None richiede Secure. I browser differiscono nel default, quindi impostalo in modo esplicito.
  • Il prefisso di nome __Host- fa rifiutare il cookie al browser a meno che sia impostato con Secure da un’origine HTTPS, con Path=/ e senza attributo Domain.

Usa Lax o Strict per i cookie di sessione, a meno che un flusso richieda davvero None, per esempio un ritorno da pagamento o accesso che invia dati da un altro sito. L’OWASP Session Management Cheat Sheet considera SameSite una difesa in profondità contro il cross-site request forgery (CSRF), non un sostituto dei token CSRF.

6. Header da eliminare: X-XSS-Protection e altri residui

  • X-XSS-Protection attivava nei vecchi browser un filtro che poteva a sua volta creare vulnerabilità XSS (MDN). OWASP indica di non impostarlo, o di disattivarlo con 0; la sostituta è la CSP.
  • Expect-CT: OWASP indica di non usarlo e, citando Mozilla, di rimuoverlo dalle configurazioni esistenti.
  • Public-Key-Pins (HPKP) è stato rimosso da Chromium nel 2018 e non è supportato da nessun browser moderno.
  • Feature-Policy è stato sostituito da Permissions-Policy.

Server e X-Powered-By nominano il tuo software, a volte con i numeri di versione. OWASP suggerisce di rimuoverli o di renderli privi di informazioni, ma la sua stessa guida al testing lo definisce security through obscurity, e MDN afferma che tenere il software aggiornato conta di più. Rimuovi i numeri di versione (in nginx, server_tokens off; rimuove la versione, non l’header) e investi lo sforzo negli aggiornamenti.

7. Una base da copiare per nginx e host statici

Questa base per nginx imposta gli header a basso rischio, avvia HSTS e CSP nelle fasi di test e reindirizza da HTTP a HTTPS sullo stesso host. Il parametro always aggiunge gli header anche alle risposte di errore.

server {
    listen 80;
    server_name example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl;
    server_name example.com;
    # qui vanno ssl_certificate e ssl_certificate_key
    server_tokens off;

    add_header Strict-Transport-Security "max-age=300" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header Cross-Origin-Opener-Policy "same-origin" always;
    add_header Content-Security-Policy-Report-Only "default-src 'self'; form-action 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'self'" always;
}

Due comportamenti documentati del modulo headers di nginx spiegano molti header mancanti. Senza always, add_header si applica solo ai codici di stato 200, 201, 204, 206, 301, 302, 303, 304, 307 e 308, quindi le pagine 404 e 500 escono senza header. Inoltre le direttive add_header sono ereditate dal livello superiore solo se il livello corrente non ne definisce nessuna: un solo add_header dentro un blocco location elimina lì tutti gli header di sicurezza del livello server. Ripeti gli header, usa include con un file condiviso oppure, da nginx 1.29.3, usa add_header_inherit merge;.

Host statici come Cloudflare Pages e Netlify leggono un file _headers distribuito con il sito. Questo esempio segue il formato documentato da Cloudflare, usato anche da Netlify:

/*
  X-Content-Type-Options: nosniff
  Referrer-Policy: strict-origin-when-cross-origin
  Permissions-Policy: camera=(), microphone=(), geolocation=()
  X-Frame-Options: SAMEORIGIN
  Content-Security-Policy-Report-Only: default-src 'self'; form-action 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'self'

Conosci i limiti. Cloudflare Pages non applica il file alle risposte generate da Pages Functions, consente fino a 100 regole di header con al massimo 2.000 caratteri per riga e unisce i valori con una virgola quando lo stesso header viene applicato due volte. Netlify applica gli header personalizzati solo ai file che serve direttamente, non a contenuti in proxy, funzioni, edge function o pagine renderizzate lato server: quelle risposte devono impostare i propri header. HSTS è escluso dall’esempio: verifica con curl che cosa invia già la piattaforma prima di aggiungerlo.

8. Rilascia per fasi ed evita gli errori più comuni

  1. Aggiungi nosniff, Referrer-Policy, Permissions-Policy e la protezione dai frame, poi testa accesso, checkout e widget incorporati.
  2. Invia la bozza di CSP come Content-Security-Policy-Report-Only. Nulla viene bloccato; le violazioni compaiono nella console del browser e, se la policy ne indica uno, in un endpoint di segnalazione. Percorri i flussi principali, comprese le pagine dopo l’accesso, e correggi la policy.
  3. Avvia HSTS con un max-age breve e aumentalo per gradi.
  4. Applica la CSP. Una policy Report-Only più rigida può restare attiva in parallelo per testare il successivo irrigidimento.
  5. Ripeti i controlli con curl dopo ogni modifica a server, CDN o framework.

Errori comuni:

  • Header solo su alcune risposte. La home page li ha; la pagina 404, l’API, i file statici o una pagina di accesso servita separatamente no.
  • Cambiare host e schema in un solo redirect. Se http://example.com reindirizza direttamente a https://www.example.com, il browser non riceve mai HSTS per example.com. Reindirizza prima a HTTPS sullo stesso host, invia HSTS su quella risposta HTTPS e solo dopo reindirizza a www.
  • La CDN sovrascrive l’origine. Una CDN o un proxy può aggiungere, sostituire, rimuovere o duplicare gli header. Decidi quale livello è responsabile di ciascun header e conferma il risultato con curl.
  • Una CSP che consente tutto. Una policy gonfiata con 'unsafe-inline', 'unsafe-eval' o * per far tacere gli errori supera un controllo di presenza ma blocca poco.
  • includeSubDomains troppo presto. Un sottodominio dimenticato che funziona solo su HTTP diventa irraggiungibile per i browser che hanno memorizzato la policy.

Gli header sono un solo livello. La checklist di lancio del sito li affianca a DNS, TLS e redirect, e la guida all’audit di sicurezza del sito tratta accessi, permessi e una routine di revisione ripetibile.

9. Come lo snapshot gratuito controlla gli header

Lo snapshot gratuito di preparazione al lancio esegue otto controlli passivi su una sola origine pubblica senza registrazione; uno di questi legge gli header di sicurezza HTTP. Non è un pentest né l’audit su sei aree.

  • Richiede la home page dell’origine inserita (percorsi e query string vengono scartati), segue fino a cinque redirect e valuta la risposta finale. Non richiede nessun’altra pagina.
  • Controlla soprattutto la presenza. Una CSP mancante, HSTS mancante su un target HTTPS e l’assenza di protezione dai frame sono valutati medi. Access-Control-Allow-Origin: *, X-Content-Type-Options diverso da nosniff, un Referrer-Policy mancante, qualsiasi header X-Powered-By e un header Server che contiene un numero di versione sono valutati bassi. Server: nginx senza versione viene mostrato a titolo informativo e non conta come segnale di rischio. I cookie impostati su quella risposta senza HttpOnly, o senza Secure su HTTPS, sono valutati medi; SameSite non viene controllato.
  • Un voto di hardening separato (da A a F) valuta gli header presenti insieme all’esito TLS e dà meno credito alla CSP quando consente 'unsafe-inline' (o 'unsafe-eval' per gli script). Permissions-Policy e COOP contano solo in questo voto.
  • Il controllo separato del redirect HTTPS dipende da ciò che inserisci. Per un dominio senza prefisso o un indirizzo https://, segnala come basso un max-age HSTS inferiore a 180 giorni, cosa attesa durante un aumento graduale, e cerca riferimenti http:// nell’HTML della pagina (contenuto misto); non verifica il redirect da HTTP a HTTPS. Il redirect viene testato solo se inserisci l’indirizzo http://, e quell’esecuzione salta il controllo TLS e non segnala l’assenza di HSTS.

Il risultato mostra un punteggio, il voto di hardening, il numero di segnali di rischio e di controlli superati, fino a tre segnali, prima i rischi, e tutti gli otto controlli con le loro valutazioni. Per gli otto header che verifica mostra la valutazione e, se disponibile, il valore osservato, non ogni header inviato dalla risposta; usa DevTools o curl per il resto e per le altre pagine.

Per aprire prima questo controllo, usa la verifica gratuita degli header di sicurezza: esegue lo stesso snapshot e mostra il controllo sugli header, aperto, sopra gli altri sette.

Domande frequenti

Come verifico gli header di sicurezza del mio sito?

In DevTools del browser apri il pannello Network, ricarica la pagina, seleziona il documento HTML e leggi Response Headers. Da terminale, curl -sS -D - -o /dev/null https://example.com/ li stampa. Controlla anche l’indirizzo http://, una pagina 404, una risposta API e un file statico, perché i loro header spesso differiscono.

Quali header di sicurezza HTTP devo impostare per primi?

Parti da X-Content-Type-Options: nosniff, Referrer-Policy, Permissions-Policy e dalla protezione dai frame, i meno propensi a rompere qualcosa; testa comunque dopo script, accesso e widget incorporati. Poi prova una Content-Security-Policy in modalità Report-Only e aumenta il max-age di HSTS per gradi.

Devo ancora inviare X-XSS-Protection?

No. Rimuovilo oppure invia X-XSS-Protection: 0 e affidati a una Content-Security-Policy. Il vecchio filtro del browser che controllava poteva a sua volta creare vulnerabilità XSS.

Mi serve X-Frame-Options se uso già frame-ancestors?

La direttiva CSP frame-ancestors lo sostituisce nei browser che la supportano. X-Frame-Options: DENY o SAMEORIGIN resta un ripiego ragionevole per i browser più vecchi, purché entrambi gli header consentano lo stesso inserimento nei frame. Non usare ALLOW-FROM: i browser moderni ignorano l’intero header quando lo trovano.

Devo aggiungere il mio dominio alla lista HSTS preload?

Di solito no. Il sito di invio del preload, hstspreload.org, ora raccomanda HSTS ma non il preload, perché Chrome e Safari convertono già in HTTPS le navigazioni HTTP. Inoltre una rimozione dall’elenco impiega mesi per raggiungere gli utenti.

Gli header di sicurezza rendono sicuro il mio sito?

Non da soli. Limitano i danni di script iniettati, clickjacking, downgrade di protocollo e furto di cookie. Non correggono codice vulnerabile, software obsoleto o un controllo degli accessi debole.

Fonti e approfondimenti

  1. MDN: guida alla Content Security Policy (CSP)developer.mozilla.org
  2. MDN: direttiva CSP frame-ancestorsdeveloper.mozilla.org
  3. MDN: header Strict-Transport-Securitydeveloper.mozilla.org
  4. MDN: header Set-Cookie e attributi dei cookiedeveloper.mozilla.org
  5. OWASP HTTP Headers Cheat Sheetcheatsheetseries.owasp.org
  6. OWASP Secure Headers Project: valori consigliatiraw.githubusercontent.com
  7. HSTS Preload List: invio del dominiohstspreload.org
  8. nginx: ngx_http_headers_module (add_header)nginx.org
  9. Cloudflare Pages: headerdevelopers.cloudflare.com
  10. Netlify: header personalizzatidocs.netlify.com
Team Sitelemetry

A cura della redazione di Sitelemetry. Le fonti collegate permettono di approfondire gli argomenti.

SITELEMETRY

Metti in pratica ciò che hai imparato.

Esplora struttura, impostazioni e segnali del tuo sito con Sitelemetry.