Security headers: HSTS, CSP, X-Frame-Options e altri
· 7 min di lettura
Il backend e una fortezza, ma meta della difesa sta nel browser. HSTS, CSP e altri header bloccano XSS, clickjacking e MITM - e sono gratis.
Perché contano
Un'applicazione può essere perfettamente sicura sul backend e restare comunque vulnerabile agli attacchi lato browser: cross-site scripting (XSS), clickjacking, protocol downgrade, MIME confusion. Gli header di sicurezza spostano la difesa nel browser stesso.
Strict-Transport-Security (HSTS)
Forza HTTPS per tutte le visite future. Dopo la prima visita via HTTPS il browser memorizza il dominio e riscrive da solo qualsiasi link http:// in https://, anche se l'utente clicca su un link sbagliato.
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
max-age=63072000= valido 2 anniincludeSubDomains= la regola vale anche per tutti i sottodomini; forza HTTPS ovunque, quindi un sottodominio che gira solo via HTTP, es.staging.example.com, diventa irraggiungibile nel browserpreload= permette l'inclusione nella lista HSTS preload incorporata in Chrome / Firefox / Safari
Attenzione:
Rimuovere un HSTS con preload dalla lista richiede 6+ mesi. Non aggiungere preload prima di aver verificato che HTTPS funzioni in modo stabile su tutti i sottodomini.
Content-Security-Policy (CSP)
L'header più potente, ma anche il più difficile da configurare. Fa whitelist di dove il browser può caricare script, stili, immagini e iframe. Senza CSP un attaccante in grado di iniettare un tag <script> può eseguire qualsiasi JS; con CSP solo codice da fonti approvate.
Content-Security-Policy: default-src 'self'; script-src 'self' 'sha256-...'; img-src 'self' data: https://cdn.example.com; style-src 'self' 'unsafe-inline'; frame-ancestors 'none'
Direttive comuni:
default-src 'self'= di default consenti solo risorse dal mio dominioscript-src= fonti JS (per gli script inline specifica un hash o una nonce)style-src= fonti CSSimg-src= immaginiconnect-src= AJAX, WebSocket, EventSourceframe-ancestors 'none'= nessuno può incorporare la pagina in un iframe (meglio di X-Frame-Options)report-uri /csp-report= il browser invia un JSON a ogni violazione (la catturi nel backend e la logghi)- Nota:
report-uriè oggi deprecated - i browser che supportanoreport-tolo ignorano. Il modo moderno è la direttivareport-topiù un headerReporting-Endpointsseparato; tienireport-urisolo come fallback per Firefox, che non supporta ancorareport-to.
X-Frame-Options
Alternativa più vecchia a frame-ancestors. Previene il clickjacking, in cui l'attaccante inserisce la tua pagina come iframe e la copre con pulsanti invisibili.
X-Frame-Options: DENY
Valori: DENY (nessuno), SAMEORIGIN (solo il mio dominio), ALLOW-FROM uri (deprecated).
X-Content-Type-Options
X-Content-Type-Options: nosniff
Disattiva il MIME sniffing, così il browser rispetta il Content-Type restituito dal server. Senza questo, un attaccante può caricare un file con tipo sbagliato (es. un'immagine che in realtà è HTML con script) e il browser può eseguirlo come pagina web.
Referrer-Policy
Referrer-Policy: strict-origin-when-cross-origin
Controlla quante informazioni sulla pagina precedente il browser invia nell'header Referer al click. Il valore predefinito nei browser moderni è già strict-origin-when-cross-origin, ma impostare l'header in modo esplicito garantisce un comportamento coerente.
Permissions-Policy
Disattiva le API che non ti servono, come camera, microfono, GPS e geolocalizzazione. Un attaccante che sfrutta XSS non può richiedere queste API.
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Configurazione pratica in nginx
server {
listen 443 ssl http2;
server_name example.com;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
# qui abbiamo omesso preload di proposito - aggiungilo solo quando sei sicuro al 100% (vedi la trappola di preload sopra)
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
# CSP è estesa - definiscila secondo la tua applicazione
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; ..." always;
}
La chiave è always - senza di esso nginx omette gli header nelle risposte di errore (4xx, 5xx).
Audit dello stato attuale
Il più semplice è uno strumento online. Il nostro header check ti mostra quali header mancano e quali sono sbagliati. Per un audit approfondito, securityheaders.com fornisce anche un punteggio A-F.
Conclusione
Gli header di sicurezza sono uno dei migliori investimenti in sicurezza per rapporto sforzo-guadagno: tipicamente mezz'ora di setup in un reverse proxy contro un'intera categoria di attacchi lato browser. Un audit una volta ogni sei mesi nell'ambito della manutenzione regolare è un minimo ragionevole.
Audit gratuito di security headers
Senza registrazione, risultato in tre secondi.
Prova ePulz.io gratis - 7 giorni senza carta di credito.
Crea account