Torna al blog

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.

Security headers: HSTS, CSP, X-Frame-Options e altri

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 anni
  • includeSubDomains = 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 browser
  • preload = 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 dominio
  • script-src = fonti JS (per gli script inline specifica un hash o una nonce)
  • style-src = fonti CSS
  • img-src = immagini
  • connect-src = AJAX, WebSocket, EventSource
  • frame-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 supportano report-to lo ignorano. Il modo moderno è la direttiva report-to più un header Reporting-Endpoints separato; tieni report-uri solo come fallback per Firefox, che non supporta ancora report-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.

Testare il sito →

Condividi: Link copiato

Prova ePulz.io gratis - 7 giorni senza carta di credito.

Crea account