Ingegneria

Header di sicurezza HTTP: cosa fa ciascuno

Sei header che bloccano intere categorie di attacchi, in ordine di priorità: funzionamento, errori comuni e i due da rimuovere definitivamente.

Gli header di sicurezza rappresentano la misura di protezione più economica per un sito web. Ognuno di essi corrisponde a una semplice riga di configurazione del server, nessuno impatta negativamente sulle prestazioni e insieme bloccano intere categorie di attacchi.

La maggior parte dei siti non ne invia alcuno.

Ecco cosa fa ciascun header, nell'ordine ideale di implementazione, e i due header che dovreste rimuovere attivamente.

Da dove iniziare: i tre che non possono rompere nulla

Questi tre header possono essere aggiunti a quasi tutti i siti web in sicurezza, con un unico rilascio.

X-Content-Type-Options: nosniff

X-Content-Type-Options: nosniff

Un solo valore, nessuna configurazione complessa, nessun effetto collaterale negativo.

Senza questo header, i browser effettuano il "MIME sniffing" dei contenuti e possono decidere che il tipo effettivo di un file differisca da quello dichiarato. Questo è il meccanismo alla base di attacchi in cui un file caricato da un utente — dichiarato come immagine — viene eseguito come JavaScript perché il suo contenuto somiglia a uno script.

Non esiste alcuna ragione valida per non inviare questo header. Se il vostro sito non lo invia, è la prima cosa da correggere.

X-Frame-Options

X-Frame-Options: SAMEORIGIN

Impedisce che le vostre pagine vengano caricate all'interno di un iframe sul sito di qualcun altro. È così che funziona il clickjacking: la pagina di un attaccante carica il vostro sito in un frame invisibile posizionato sotto un pulsante esca, e il clic della vittima finisce invece sulla vostra interfaccia.

SAMEORIGIN consente al vostro stesso sito di includersi in frame, che è solitamente ciò che desiderate. DENY blocca completamente qualsiasi framing.

Il sostituto moderno è frame-ancestors all'interno della CSP, che offre maggiore flessibilità. Inviarli entrambi non costa nulla e garantisce la compatibilità con i browser più datati.

Referrer-Policy

Referrer-Policy: strict-origin-when-cross-origin

Controlla quanta parte dell'URL corrente viene inviata quando qualcuno clicca su un link verso un altro sito.

Senza di esso, l'URL completo rischia di trapelare — compresi eventuali dati presenti nella query string. Token di ripristino password, identificatori di sessione, termini di ricerca interni e ID cliente sono tutti trapelati in questo modo a terze parti.

strict-origin-when-cross-origin invia l'URL completo all'interno del vostro sito, solo l'origine (il dominio) verso altri siti HTTPS e nulla quando si passa a una connessione HTTP non sicura. È ormai l'impostazione predefinita dei browser moderni, ma impostarlo esplicitamente copre i client più datati e documenta chiaramente l'intento.

Il passo successivo: HSTS

Strict-Transport-Security: max-age=31536000; includeSubDomains

Indica al browser di connettersi a questo dominio esclusivamente tramite HTTPS per il periodo specificato, senza nemmeno tentare prima una richiesta HTTP.

I vantaggi sono due. Il primo riguarda la sicurezza: chiude la finestra temporale in cui una richiesta HTTP iniziale potrebbe essere intercettata e declassata prima che scatti il reindirizzamento. Il secondo riguarda le prestazioni ed è spesso trascurato: elimina completamente il redirect da http a https per i visitatori ricorrenti, risparmiando un intero round-trip su ogni caricamento di pagina.

Rilasciatelo con cautela. L'HSTS è un vincolo rigoroso che i browser applicano rigidamente e che non potete revocare all'istante. Se impostate un max-age di un anno con includeSubDomains e poi scoprite un sottodominio interno che supporta solo HTTP, quel sottodominio risulterà inaccessibile per chiunque abbia visitato il vostro sito — fino a un anno.

Il percorso sicuro:

  1. Verificate che ogni sottodominio gestisca correttamente HTTPS.
  2. Rilasciate con max-age=300 per qualche giorno.
  3. Aumentate a max-age=86400 per una settimana.
  4. Infine impostate max-age=31536000; includeSubDomains.

La direttiva preload va ancora oltre, inserendo il vostro dominio direttamente negli elenchi HSTS predefiniti dei browser. La rimozione richiede mesi. Aggiungetela solo quando ne siete assolutamente certi.

La protezione principale: Content-Security-Policy

La CSP dichiara da quali sorgenti la pagina è autorizzata a caricare script, fogli di stile, immagini, font e connessioni di rete. Quando è configurata correttamente, blocca la maggior parte degli attacchi cross-site scripting anche qualora un'iniezione di codice dovesse riuscire — lo script iniettato non possiede un'origine consentita, quindi il browser si rifiuta di eseguirlo.

È anche l'unico header di questa lista che può compromettere il funzionamento del sito se errato, motivo per cui così pochi siti lo adottano.

Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; frame-ancestors 'self'; base-uri 'self'; form-action 'self'

Il problema di unsafe-inline. La maggior parte dei siti contiene blocchi <script> inline — snippet di analytics, tag manager, piccoli frammenti di logica specifica della pagina. Una CSP rigida li blocca tutti. Aggiungere 'unsafe-inline' a script-src fa funzionare la policy senza errori ma al tempo stesso ne vanifica gran parte del valore, perché gli script inline sono esattamente ciò che la CSP dovrebbe bloccare.

La vera soluzione sono i nonce o gli hash: generate un nonce casuale per ogni richiesta, assegnatelo agli script inline legittimi e referenziatelo nella policy. Questo richiede il rendering lato server del nonce, motivo per cui comporta più lavoro rispetto a una singola riga di configurazione.

Rilasciate prima in modalità report-only:

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

Nessuna risorsa viene bloccata; le violazioni vengono solo segnalate. Mantenetelo attivo da due a quattro settimane, analizzate cosa viene segnalato, autorizzate le risorse legittime e infine modificate il nome dell'header per applicare il blocco.

Quattro direttive economiche e utili anche in una policy flessibile: frame-ancestors (contro il clickjacking), base-uri (impedisce ai tag <base> iniettati di reindirizzare gli URL relativi), form-action (impedisce l'invio di form iniettati verso destinazioni esterne) e object-src 'none' (elimina i vettori di attacco tramite plugin in stile Flash).

Permissions-Policy

Permissions-Policy: geolocation=(), microphone=(), camera=(), payment=()

Dichiara quali funzionalità del browser possono essere utilizzate dalla pagina. Negare ciò che non viene utilizzato limita le capacità a cui uno script di terze parti compromesso può accedere. Se il vostro sito non richiede mai l'accesso alla fotocamera, dichiararlo non costa nulla e revoca tale autorizzazione a ogni script presente sulla pagina — inclusi quelli che non avete verificato direttamente.

Due header da rimuovere

X-XSS-Protection è obsoleto. Abilitava un filtro XSS lato browser che è stato rimosso da Chrome ed Edge perché il filtro stesso introduceva vulnerabilità. Inviarlo non serve a nulla e la sua presenza segnala solitamente una configurazione copiata da una guida scritta dieci anni fa.

Server e X-Powered-By con numeri di versione pubblicizzano esattamente quale software state eseguendo. Quando viene resa nota una vulnerabilità, le scansioni automatizzate cercano proprio queste informazioni. Rimuoveteli:

Header unset X-Powered-By
Header unset Server
ServerTokens Prod

Configurazione Apache / LiteSpeed

Questo copre la maggior parte degli hosting condivisi, incluso Hostinger. Nel file .htaccess:

<IfModule mod_headers.c>
  Header always set X-Content-Type-Options "nosniff"
  Header always set X-Frame-Options "SAMEORIGIN"
  Header always set Referrer-Policy "strict-origin-when-cross-origin"
  Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
  Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" env=HTTPS
  Header unset X-Powered-By
</IfModule>

La parola chiave always è fondamentale — senza di essa l'header verrebbe omesso dalle risposte di errore, che è esattamente il momento in cui ne avete più bisogno.

Su Nginx l'equivalente è add_header … always; all'interno del blocco server.

Come verificare la configurazione

Potete verificare gli header di risposta effettivi di qualsiasi sito con il nostro free security headers scanner. Analizza gli header reali restituiti dal server, assegna una valutazione a quelli presenti e segnala i valori deboli specificandone la ragione — una CSP con unsafe-inline riceve una valutazione diversa rispetto a una CSP senza di essa.

Ordine di priorità

  1. X-Content-Type-Options — una riga, nessun rischio
  2. X-Frame-Options — una riga, nessun rischio
  3. Referrer-Policy — una riga, nessun rischio
  4. Rimuovere X-XSS-Protection e gli header di versione
  5. Permissions-Policy — disabilitare le feature non utilizzate
  6. HSTS — rilascio graduale a scaglioni
  7. CSP — report-only iniziale, poi applicazione effettiva

I passaggi da 1 a 5 richiedono un singolo rilascio e un pomeriggio di lavoro. I passaggi 6 e 7 richiedono maggiore attenzione. Implementare anche solo i primi cinque mette il vostro sito in una posizione di sicurezza superiore alla maggior parte del web.

Una precisazione trasparente: nessuno di questi header costituisce un fattore diretto di posizionamento SEO. Nessun motore di ricerca valuta direttamente la vostra CSP. La ragione per implementarli è che un sito compromesso perde il posizionamento molto rapidamente non appena Google lo segnala come violato — e a quel punto risolvere il problema è immensamente più costoso di un file di configurazione.

Continua a leggere

Diteci quali obiettivi volete raggiungere.

Un solo team. Tre uffici. Ventisei lingue. Inviateci il problema e riceverete una risposta tecnica qualificata — non un copione di vendita.

Una proposta scritta entro un giorno lavorativo, nella vostra lingua.