Security Headers: 6 Righe di Configurazione che Bloccano il 70% degli Attacchi Web
Gli header HTTP di sicurezza sono la difesa più sottovalutata in WordPress. Non servono plugin. Non servono soldi. Servono 6 righe nella configurazione del web server. E bloccano intere categorie di attacchi: clickjacking, XSS, MIME sniffing, downgrade HTTPS.
Il 73% dei siti WordPress non ha security headers configurati (SecurityHeaders.com lo verifica in 2 secondi). Questo include siti di agenzie, e-commerce, e persino PA. Zero scuse.
I 6 Header che Ogni Sito WordPress Deve Avere
1. X-Frame-Options
Impedisce che il tuo sito venga caricato in un iframe su un altro dominio. Senza questo header, un attaccante può creare una pagina che mostra il tuo sito in un iframe trasparente sopra contenuti ingannevoli (clickjacking).
# Nginx
add_header X-Frame-Options "SAMEORIGIN" always;
# Apache (.htaccess)
Header always set X-Frame-Options "SAMEORIGIN"
Valori: DENY (nessun iframe, mai), SAMEORIGIN (solo dal tuo dominio), ALLOW-FROM uri (deprecato, non usarlo).
Usa SAMEORIGIN a meno che tu non abbia motivi specifici per DENY. Alcuni plugin WordPress usano iframe interni (Customizer, post preview).
2. X-Content-Type-Options
Impedisce al browser di “indovinare” il tipo MIME di un file. Senza questo header, un file .txt con contenuto JavaScript potrebbe essere eseguito come script (MIME sniffing attack).
# Nginx
add_header X-Content-Type-Options "nosniff" always;
# Apache
Header always set X-Content-Type-Options "nosniff"
Un solo valore possibile: nosniff. Nessun motivo per non aggiungerlo.
3. Strict-Transport-Security (HSTS)
Forza il browser a usare HTTPS per tutte le richieste future al tuo dominio. Senza HSTS, un attaccante su una rete WiFi pubblica può intercettare la prima richiesta HTTP (prima del redirect a HTTPS) e fare un downgrade attack.
# Nginx
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# Apache
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
max-age=31536000 = 1 anno. includeSubDomains = vale anche per i sottodomini. preload = il dominio può essere inserito nella HSTS preload list dei browser.
Attenzione: abilita HSTS solo se sei sicuro al 100% che HTTPS funziona su tutto il sito (inclusi sottodomini). Se HTTPS si rompe con HSTS attivo, il sito diventa inaccessibile per max-age secondi.
4. Referrer-Policy
Controlla quante informazioni il browser invia nell’header Referer quando un utente clicca un link che porta fuori dal tuo sito.
# Nginx
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Apache
Header always set Referrer-Policy "strict-origin-when-cross-origin"
strict-origin-when-cross-origin: invia l’URL completo per richieste same-origin, solo l’origine per cross-origin, nulla se da HTTPS a HTTP. Il bilanciamento migliore tra privacy e funzionalità (Google Analytics, etc. continuano a funzionare).
5. Permissions-Policy (ex Feature-Policy)
Controlla quali API del browser il tuo sito può usare: geolocation, camera, microfono, payment. Se non usi queste feature, disabilitale esplicitamente.
# Nginx
add_header Permissions-Policy "geolocation=(), camera=(), microphone=(), payment=()" always;
# Apache
Header always set Permissions-Policy "geolocation=(), camera=(), microphone=(), payment=()"
Il valore () significa “nessuno” (disabilitato). Se il tuo sito usa la geolocation, cambia in geolocation=(self).
6. Content-Security-Policy (CSP)
Il più potente e il più complesso. CSP definisce da dove il browser può caricare risorse (script, stili, immagini, font). Un CSP ben configurato blocca la quasi totalità degli attacchi XSS.
Il problema: WordPress e i suoi plugin caricano risorse da decine di origini diverse. Un CSP troppo restrittivo rompe il sito. Un CSP troppo lasso non serve a nulla.
Approccio consigliato per WordPress: inizia in report-only e affina:
# Nginx - Fase 1: solo reporting (non blocca nulla)
add_header Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; report-uri /csp-report" always;
Monitora i report per 2 settimane. Vedi cosa viene bloccato. Aggiungi le origini legittime. Poi attiva il CSP reale (senza -Report-Only).
Un CSP minimo ma funzionale per WordPress:
# Nginx - CSP base per WordPress
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.google-analytics.com https://www.googletagmanager.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; frame-src 'self' https://www.youtube.com; connect-src 'self' https://www.google-analytics.com" always;
Nota: 'unsafe-inline' e 'unsafe-eval' sono necessari per la maggior parte dei temi e plugin WordPress. Non ideale dal punto di vista sicurezza, ma rimuoverli rompe quasi tutto. Un tradeoff pragmatico.
Configurazione Completa per Nginx
# /etc/nginx/snippets/security-headers.conf
# Include questo file nei server block: include snippets/security-headers.conf;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), camera=(), microphone=(), payment=()" always;
Poi nel server block di ogni sito:
server {
listen 443 ssl http2;
server_name tuosito.com;
include snippets/security-headers.conf;
# ... resto della configurazione
}
Un file snippet condiviso per tutti i siti. Cambi in un posto, si applica ovunque.
Come Verificare gli Header
# Da terminale
curl -I https://tuosito.com
# Output atteso:
# X-Frame-Options: SAMEORIGIN
# X-Content-Type-Options: nosniff
# Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
# Referrer-Policy: strict-origin-when-cross-origin
# Permissions-Policy: geolocation=(), camera=(), microphone=(), payment=()
Online: securityheaders.com analizza il tuo sito e assegna un grade da A+ a F. L’obiettivo è A o A+.
GEO Optimizer include un check dei meta tag nell’audit (sezione 4), ma per i security headers un tool dedicato come SecurityHeaders.com è più preciso.
FAQ
Posso aggiungere security headers con un plugin WordPress?
Sì, plugin come “HTTP Headers” o “Headers Security Advanced & HSTS WP” li aggiungono via PHP. Funziona, ma è meno efficiente che farlo a livello server: il plugin carica WordPress prima di aggiungere gli header, mentre la configurazione Nginx/Apache li aggiunge prima ancora che PHP si avvii. Per siti in produzione, preferisci la configurazione server.
HSTS può bloccare il mio sito?
Sì, se HTTPS smette di funzionare (certificato scaduto, configurazione rotta). Con HSTS attivo, il browser rifiuta la connessione HTTP per max-age secondi. Per sicurezza: imposta max-age a 300 (5 minuti) inizialmente, verifica che tutto funzioni, poi alzalo a 31536000 (1 anno).
CSP rompe il mio sito WordPress. Cosa faccio?
Usa Content-Security-Policy-Report-Only prima. Non blocca nulla, ma logga le violazioni. Dopo 2 settimane di report, sai esattamente quali origini aggiungere. Poi passa al CSP reale. È un processo iterativo, non un’azione singola.