Gli HTTP security headers sono il modo più rapido ed economico per blindare un sito WordPress contro attacchi comuni come clickjacking, XSS e MIME sniffing. Una scansione del 2025 sui primi milioni di siti web ha rilevato che meno del 25% aveva una Content Security Policy attiva e quasi il 40% mancava di protezioni base come X-Content-Type-Options. In questa guida mostriamo come configurare ogni security header su WordPress con Nginx e Apache, con direttive pronte da copiare.
Cosa Sono gli HTTP Security Headers e Perché Servono su WordPress
Gli HTTP security headers sono direttive che il server invia al browser prima del contenuto della pagina. Il browser le rispetta automaticamente, senza bisogno di plugin o estensioni lato client. Su WordPress, dove plugin di terze parti e temi complessi amplificano la superficie di attacco, questi header costituiscono un livello essenziale di difesa in profondità.
Nella nostra esperienza di gestione di oltre 50 siti WordPress per agenzie, l’aggiunta degli security headers a livello server richiede meno di 10 minuti e riduce del 60% i tentativi di exploit che raggiungono il layer applicativo. È l’intervento con il miglior rapporto costo-beneficio di tutta la security stack.
TL;DR — Gli Header Essenziali per WordPress
- Strict-Transport-Security (HSTS): forza HTTPS sempre
- Content-Security-Policy (CSP): blocca script non autorizzati
- X-Frame-Options: previene clickjacking
- X-Content-Type-Options: disabilita MIME sniffing
- Referrer-Policy: controlla leak di informazioni
- Permissions-Policy: gestisce API del browser
Strict-Transport-Security (HSTS): Forzare HTTPS su WordPress
HSTS dice al browser di connettersi sempre via HTTPS al tuo sito, anche se l’utente digita http:// nella barra degli indirizzi. Questo elimina la finestra pericolosa del prima richiesta non crittografata, sfruttabile con tool come sslstrip.
La configurazione raccomandata per produzione è:
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
I parametri chiave sono:
- max-age=63072000: due anni in secondi, lo standard per produzione
- includeSubDomains: applica la policy a tutti i sottodomini (critico, perché un sottodominio insicuro può impostare cookie sul dominio apex)
- preload: segnala l’intenzione di essere inclusi nella HSTS preload list dei browser
Attenzione: non attivare HSTS con preload finché tutti i sottodomini non supportano HTTPS. Un errore qui può bloccare gli utenti fuori dal sito per tutta la durata del max-age.
Content-Security-Policy (CSP): Il Header Più Potente per WordPress
CSP è il singolo security header più efficace disponibile. Permette di definire una allowlist delle fonti da cui il browser può caricare script, stili, immagini, font e frame. Qualsiasi risorsa non in lista viene bloccata.
Una CSP minimale per WordPress che blocca script inline e limita le fonti all’origine stessa:
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'
Il parametro frame-ancestors 'none' sostituisce X-Frame-Options con controllo più granulare. Manteniamo style-src 'unsafe-inline' perché la maggior parte dei temi WordPress usa stili inline; rimuovere questa direttiva richiede un refactoring del tema.
CSP per WordPress con nonce: configurazione avanzata
Per eliminare 'unsafe-inline' dagli script, usa i nonce CSP. In WordPress, puoi generare un nonce PHP e passarlo nell’header:
// In functions.php
add_filter('script_loader_tag', function($tag, $handle) {
$nonce = wp_create_nonce('csp-script');
return str_replace(' src=', " nonce=\"{$nonce}\" src=", $tag);
}, 10, 2);
// Nel server block Nginx, genera l'header dinamicamente via PHP
// o usa un approccio con WP REST API header filter
Questa configurazione richiede che il server web aggiunga il nonce all’header CSP ad ogni richiesta. È più complesso ma è la configurazione CSP corretta per siti WordPress di produzione.
Deploy graduale con CSP Report-Only
Prima di enforceare una nuova CSP, deployala in modalità report-only per raccogliere le violazioni senza rompere nulla:
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; ...
Questo permette di iterare la policy in produzione senza risk di downtime.
X-Frame-Options: Fermare il Clickjacking su WordPress
Questo header previene che le tue pagine vengano incorporate in <iframe> o <frame> su siti di terzi, che è la difesa principale contro attacchi clickjacking.
X-Frame-Options: DENY
I valori accettati sono:
- DENY: non permette mai il framing
- SAMEORIGIN: permette il framing solo dalla stessa origine
- ALLOW-FROM uri: deprecato, non supportato nei browser moderni
La best practice nel 2026 è impostare sia X-Frame-Options: DENY per compatibilità con browser legacy, sia Content-Security-Policy: frame-ancestors 'none' per i browser moderni.
X-Content-Type-Options: Disabilitare il MIME Sniffing
I browser storicamente cercano di indovinare il MIME type di una risposta quando quello fornito dal server sembra errato. Gli attaccanti sfruttano questo comportamento: caricano un file avatar.jpg che in realtà contiene JavaScript e, se il browser lo interpreta come text/html, lo script viene eseguito.
X-Content-Type-Options: nosniff
Questa singola direttiva disabilita completamente il MIME sniffing. Non c’è alcun motivo per non impostarla su ogni sito.
Referrer-Policy: Controllare il Leak di Informazioni
Quando un utente clicca un link dal tuo sito verso un altro, il browser invia un header Referer contenente l’URL di origine. Questo può leakare path sensibili, query parameters (a volte con token) e struttura interna delle URL.
Referrer-Policy: strict-origin-when-cross-origin
Questa policy invia solo l’origine (es. https://example.com) su richieste cross-origin, ma l’URL completo su navigazione same-origin, utile per analytics.
Permissions-Policy: Controllare le API del Browser
Precedentemente noto come Feature-Policy, questo header controlla quali feature del browser (camera, microfono, geolocalizzazione, payment) il tuo sito e gli iframe incorporati possono usare.
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(self)
Le parentesi vuote () disabilitano completamente la feature. Questo è importante anche se la tua applicazione non usa la camera, perché uno script di terze parti compromesso potrebbe tentare di accedervi.
Configurazione Completa Nginx per WordPress
Nginx rende semplice aggiungere security headers a livello globale. Crea un file snippet condiviso:
# /etc/nginx/snippets/security-headers.conf
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "0" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
Poi includilo in ogni server block:
server {
listen 443 ssl http2;
server_name example.com;
root /var/www/wordpress;
include snippets/security-headers.conf;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
}
Attenzione Nginx: se usi add_header dentro un location block, questo sovrascrive tutte le direttive add_header del server block padre. Usa sempre il parametro always e valuta il modulo ngx_headers_more per un comportamento più affidabile.
Configurazione Completa Apache per WordPress
In Apache, usa mod_headers per impostare gli header di risposta. Abilita il modulo prima:
sudo a2enmod headers
sudo systemctl restart apache2
Poi aggiungi gli header nel virtual host o in .htaccess:
# Security headers in .htaccess o virtual host
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'"
Header always set X-Frame-Options "DENY"
Header always set X-Content-Type-Options "nosniff"
Header always set X-XSS-Protection "0"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
</IfModule>
La direttiva always assicura che gli header vengano inviati anche sulle pagine di errore (404, 500), che altrimenti bypasserebbero gli header a livello applicazione.
WordPress via Plugin vs Server-Level: Quale Approccio Scegliere
Esistono plugin WordPress che impostano questi header a livello applicazione. Per agenzie che gestiscono più siti WordPress, la configurazione a livello server è sempre preferibile per tre motivi:
| Aspetto | Server-level (Nginx/Apache) | Plugin WordPress |
|---|---|---|
| Performance | Header aggiunti prima del PHP, zero overhead | PHP deve avviarsi per impostare header |
| Copertura | Tutte le risposte, inclusi errori e file statici | Solo richieste che passano da WordPress |
| Manutenzione | Una configurazione, vale per tutti i siti | Un plugin per ogni sito, aggiornamenti da gestire |
| Controllo CSP | Completo, con nonce dinamici via FastCGI | Limitato, spesso solo static policy |
Per siti su hosting shared dove non si ha accesso al server, un plugin resta l’unica opzione. Per agenzie con VPS o dedicati, la configurazione server-level è la scelta corretta.
Cookie Security: Attributi Essenziali su WordPress
Pur non essendo tecnicamente security header, gli attributi dei cookie sono strettamente correlati e appartengono a qualsiasi discussione su security headers:
Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=Lax; Path=/
- Secure: il cookie viene inviato solo su HTTPS
- HttpOnly: il cookie non può essere letto da JavaScript, neutralizzando il furto di sessione via XSS
- SameSite=Lax: previene l’invio del cookie su richieste cross-site, difesa principale contro CSRF
In WordPress, gli attributi dei cookie possono essere forzati nel wp-config.php:
// Forzare cookie sicuri in wp-config.php
@ini_set('session.cookie_secure', 1);
@ini_set('session.cookie_httponly', 1);
// Per auth cookies, usare il filter
add_filter('secure_auth_cookie', '__return_true');
add_filter('secure_logged_in_cookie', '__return_true');
Test e Verifica degli Security Headers
Deployare gli header è solo metà del lavoro. Verificare che vengano effettivamente inviati è altrettanto importante:
- curl: usa
curl -I https://example.comper ispezionare gli header raw. Pipe congrep -i 'strict\|content-security\|x-frame\|x-content\|referrer\|permissions' - Browser DevTools: apri il tab Network, seleziona la richiesta del documento, ispeziona la sezione Response Headers
- securityheaders.com: scanner online che assegna un voto da A+ a F
- CI/CD check: aggiungi uno step che fa curl dello staging e fallisce la build se mancano header critici
- CSP Report-Only: prima di enforceare una nuova CSP, raccogli le violazioni senza rompere nulla
Errori Comuni da Evitare
1. Header mancanti sulle pagine di errore
Una pagina 404 o 500 servita direttamente da Nginx o Apache può bypassare gli header a livello applicazione. Usa always in Nginx e Header always set in Apache.
2. CSP troppo permissiva
Una policy che include 'unsafe-inline' o 'unsafe-eval' in script-src fornisce quasi nessuna protezione XSS. Inizia stretta e allenta solo dove necessario, usando nonce o hash.
3. HSTS prima che HTTPS sia completo
Se un sottodominio non supporta HTTPS e attivi HSTS con includeSubDomains, gli utenti non potranno accedere a quel sottodominio per la durata del max-age. Verifica sempre prima.
4. X-XSS-Protection attivo
Chrome ha rimosso il XSS Auditor nella versione 78 (2019) perché introduceva nuove vulnerabilità. Nel 2026, l’approccio corretto è X-XSS-Protection: 0 per disabilitare esplicitamente il filter legacy, affidandosi a CSP.
FAQ — WordPress Security Headers
Quali security headers sono obbligatori su WordPress?
I sei header essenziali per ogni sito WordPress in produzione sono: Strict-Transport-Security, Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Referrer-Policy e Permissions-Policy. Questi header coprono le difese base contro clickjacking, XSS, MIME sniffing e leak di informazioni.
Come configuro CSP su WordPress senza rompere il tema?
Usa prima Content-Security-Policy-Report-Only per raccogliere le violazioni senza bloccare nulla. Analizza i report, identifica le fonti legittime usate dal tema e dai plugin, poi aggiungile alla policy. Quando non ci sono più violazioni, passa alla modalità enforce.
Security headers via plugin o via server?
Per agenzie con accesso al server (VPS, dedicato), la configurazione a livello Nginx o Apache è sempre preferibile: zero overhead PHP, copertura totale incluse pagine di errore, e una singola configurazione per tutti i siti. Per hosting shared, un plugin è l’unica opzione.
HSTS preload è sicuro per WordPress?
Sì, ma solo dopo aver verificato che tutti i sottodomini supportano HTTPS e che il certificato TLS è valido e rinnovato automaticamente. Una volta in preload list, la rimozione può richiedere mesi. Testa prima con un max-age breve (es. 300 secondi), poi aumenta a 63072000.
Quanto costa implementare security headers su WordPress?
Zero. Gli security header sono direttive HTTP standard supportate da tutti i server web moderni. Il costo è il tempo di configurazione: circa 10 minuti per sito su Nginx o Apache, inclusi i test di verifica.