Introduzione
Quando si protegge un’applicazione PHP, spesso l’attenzione si concentra su password, sessioni, query SQL e validazione degli input. Esiste però un ulteriore livello di difesa, semplice da implementare ma molto importante: la configurazione degli HTTP Security Headers.
Gli header HTTP sono informazioni inviate dal server al browser insieme alla risposta. Possono indicare al browser come gestire il contenuto ricevuto, quali funzionalità consentire e quali comportamenti bloccare. Una configurazione corretta aiuta a ridurre rischi come il clickjacking, l’interpretazione errata dei file, il tracciamento tramite referrer e alcune forme di downgrade da HTTPS a HTTP.
In questo tutorial costruiremo un piccolo file PHP riutilizzabile per inviare header di sicurezza comuni. L’argomento è diverso dalla Content Security Policy, che merita una trattazione separata: qui ci concentreremo sugli header complementari e sulle relative buone pratiche.
Codice completo
Creiamo un file chiamato security_headers.php. È consigliabile includerlo all’inizio di ogni richiesta, prima di produrre qualsiasi output HTML.
<?php
declare(strict_types=1);
/*
* Gli header devono essere inviati prima di qualsiasi output.
* Per questo il file viene incluso all´inizio dello script.
*/
// Impedisce al browser di interpretare un file con un MIME type diverso
// da quello dichiarato dal server.
header(´X-Content-Type-Options: nosniff´);
// Impedisce l´inserimento della pagina dentro iframe di altri siti.
// SAMEORIGIN consente eventualmente l´inserimento solo dallo stesso sito.
header(´X-Frame-Options: SAMEORIGIN´);
// Limita le informazioni inviate nell´header Referer.
header(´Referrer-Policy: strict-origin-when-cross-origin´);
// Disabilita alcune API e funzionalità non necessarie.
// L´elenco può essere modificato in base alle esigenze dell´applicazione.
header(´Permissions-Policy: geolocation=(), microphone=(), camera=()´);
// Indica al browser di non interpretare la risposta come contenuto
// destinato al download automatico.
header(´Content-Disposition: inline´);
// HSTS: usare solo se il sito funziona esclusivamente in HTTPS.
// max-age espresso in secondi: due anni.
if (
isset($_SERVER[´HTTPS´]) &&
$_SERVER[´HTTPS´] !== ´off´
) {
header(
´Strict-Transport-Security: max-age=63072000; includeSubDomains´
);
}
// Header applicativo di esempio.
header(´Content-Type: text/html; charset=UTF-8´);
?> Un possibile file PHP che utilizza questa configurazione è il seguente:
<?php
require_once __DIR__ . ´/security_headers.php´;
?>
<!doctype html>
<html lang="it">
<head>
<meta charset="UTF-8">
<title>Area riservata</title>
</head>
<body>
<h1>Benvenuto nell´area riservata</h1>
<p>Gli header di sicurezza sono stati applicati dal server.</p>
</body>
</html> Spiegazione
X-Content-Type-Options
L’header X-Content-Type-Options: nosniff impedisce al browser di effettuare il cosiddetto MIME sniffing. Senza questa protezione, un file dichiarato come immagine potrebbe essere interpretato in modo diverso se il suo contenuto sembrasse codice eseguibile. L’header obbliga il browser a rispettare il tipo MIME comunicato dal server.
X-Frame-Options
Il clickjacking consiste nel mostrare una pagina legittima dentro un iframe invisibile o camuffato, inducendo l’utente a fare clic su elementi che non riconosce. Con SAMEORIGIN, la pagina può essere incorporata soltanto da documenti appartenenti alla stessa origine. Se non è necessario alcun iframe, è possibile usare:
header(´X-Frame-Options: DENY´); Questo blocca completamente l’inserimento della pagina in un frame.
Referrer-Policy
Il referrer può contenere informazioni sull’URL della pagina precedente. La direttiva strict-origin-when-cross-origin invia l’URL completo durante la navigazione sullo stesso sito, ma limita le informazioni quando la richiesta è diretta verso un dominio differente. È un buon compromesso tra funzionalità e riservatezza.
Permissions-Policy
Questo header consente di disabilitare funzionalità del browser che l’applicazione non utilizza, come fotocamera, microfono o geolocalizzazione. Ridurre le API disponibili limita l’impatto di eventuali vulnerabilità presenti nel codice o in librerie di terze parti.
Strict-Transport-Security
HSTS indica al browser di utilizzare HTTPS per le richieste future. L’opzione includeSubDomains estende la regola ai sottodomini. Deve essere attivata soltanto quando ogni sottodominio è configurato correttamente con HTTPS: in caso contrario, alcune pagine potrebbero diventare irraggiungibili.
Best practice
- Invia gli header prima di qualsiasi spazio, testo o markup HTML. Anche un carattere fuori dal tag PHP può causare l’errore “headers already sent”.
- Usa HTTPS in produzione e configura correttamente certificati, redirect e domini.
- Non attivare HSTS alla cieca: verifica prima tutti i sottodomini e considera inizialmente un valore di
max-agepiù breve. - Personalizza
Permissions-Policyin base alle funzionalità reali dell’applicazione, invece di copiare direttive inutili. - Verifica gli header tramite gli strumenti per sviluppatori del browser oppure con il comando
curl -I https://esempio.test. - Configura gli stessi header anche sul web server o su un reverse proxy, se possibile. In questo modo la protezione resta attiva anche per risposte generate da altri componenti.
- Non considerare gli header una sostituzione per autenticazione, autorizzazione, validazione o gestione sicura delle sessioni: sono un livello aggiuntivo di difesa.
- Testa l’applicazione dopo ogni modifica, soprattutto se utilizza iframe, API del browser o risorse provenienti da sottodomini diversi.
Riepilogo
Gli HTTP Security Headers permettono di aggiungere al browser regole di sicurezza direttamente dalle risposte PHP. X-Content-Type-Options riduce i rischi legati al MIME sniffing, X-Frame-Options contrasta il clickjacking, Referrer-Policy limita la diffusione degli URL e Permissions-Policy disabilita funzionalità non necessarie. HSTS, infine, rafforza l’uso obbligatorio di HTTPS.
Una soluzione pratica consiste nel centralizzare questi header in un file incluso all’inizio degli script PHP. La configurazione deve però essere verificata nell’ambiente reale, perché direttive troppo restrittive possono interrompere funzionalità legittime.
