In breve: con expose_php = Off in php.ini scompare l'header X-Powered-By: PHP/…. A ciò si aggiungono server_tokens off; in Nginx e ServerTokens Prod e ServerSignature Off in Apache. Non rende più sicuro alcun server, ma toglie alle scansioni automatiche un elenco di versioni già pronto. Il proprio livello di patch lo verifica poi tramite gestione dei pacchetti e processi, non tramite gli header.
Il biglietto da visita in ogni risposta
Chi dopo il 21 ottobre 2026 voleva sapere quanti server mostrano ancora una vecchia versione di PHP non doveva cercare a lungo. Molti server web indicano la versione di PHP in ogni singola risposta, ad esempio come X-Powered-By: PHP/8.2.20. I servizi di ricerca a livello di Internet leggono queste indicazioni, e Unit 42 di Palo Alto Networks ha contato per PHP2Shell più di 22,6 milioni di istanze esposte e potenzialmente vulnerabili.
Per gli aggressori un'indicazione simile è una scorciatoia. Possono preordinare i bersagli invece di provare alla cieca. Per i gestori, invece, è inutile, perché non prova nemmeno il proprio livello di patch: le distribuzioni consegnano spesso le correzioni come backport senza un nuovo numero di versione.
Questo articolo mostra dove PHP e server web rivelano informazioni di versione e come disattivarle. Dice anche apertamente che cosa si ottiene e che cosa no.
Dove compaiono ovunque le indicazioni di versione
La versione di PHP è solo uno dei punti. Vale la pena di guardare tutto, perché un singolo punto dimenticato svaluta le altre misure.
| Punto | Esempio | Disattivare tramite |
|---|---|---|
| Header HTTP di PHP | X-Powered-By: PHP/8.3.x |
expose_php = Off in php.ini |
| Header HTTP del server web | Server: nginx/1.x o Server: Apache/2.4.x (Debian) |
server_tokens off; o ServerTokens Prod |
| Pagine di errore del server web | riga di versione sotto le pagine 404 o 500 | le stesse impostazioni, in Apache inoltre ServerSignature Off |
| Header dell'applicazione | indicazioni X-Powered-By proprie dei framework |
fastcgi_hide_header o Header unset |
| File nel webroot | file di prova phpinfo(), file readme e changelog |
cancellare o bloccare |
| Messaggi di errore di PHP | percorsi e dettagli di versione nel browser | display_errors = Off |
I file di prova con phpinfo() sono la fonte più fruttuosa per gli aggressori. Rivelano non solo la versione, ma l'intera configurazione; maggiori informazioni nell'articolo File phpinfo(): perché devono sparire.
Disattivare expose_php in php.ini
Secondo il manuale PHP, expose_php è attivo per impostazione predefinita e modificabile solo in php.ini, non nel pool, non tramite .htaccess e non in fase di esecuzione. Imposti quindi il valore nel php.ini di ogni modalità di esercizio che consegna siti web, cioè su Debian e Ubuntu ad esempio in /etc/php/<version>/fpm/ ed eventualmente /etc/php/<version>/apache2/.
; php.ini della SAPI web, poi riavviare PHP-FPM o Apache
expose_php = Off
Se girano più versioni di PHP in parallelo, ognuna richiede la propria voce. Il riavvio del rispettivo servizio è obbligatorio, perché PHP legge il php.ini solo all'avvio.
Ridurre gli header Server in Nginx e Apache
Nginx indica per impostazione predefinita la sua versione nell'header Server e nelle pagine di errore. Con server_tokens off; resta solo il nome del prodotto. Inoltre, un header X-Powered-By che l'applicazione imposta da sé si può filtrare con fastcgi_hide_header. Secondo la documentazione di Nginx, Nginx nasconde da solo solo Status e X-Accel-…, non X-Powered-By.
# nel blocco http, vale per tutti i siti
server_tokens off;
fastcgi_hide_header X-Powered-By;
In Apache ServerTokens controlla l'header Server e al tempo stesso la riga di versione sotto le pagine di errore. Secondo la documentazione di Apache, l'impostazione vale solo a livello di server, non per VirtualHost. Poiché le risposte di PHP-FPM tramite mod_proxy_fcgi finiscono in una tabella di header diversa rispetto alle risposte del server stesso, imposti la rimozione in entrambe le varianti.
# configurazione a livello di server, ad es. /etc/apache2/conf-available/security.conf
ServerTokens Prod
ServerSignature Off
# richiede mod_headers
<IfModule mod_headers.c>
Header unset X-Powered-By
Header always unset X-Powered-By
</IfModule>
Verifichi la configurazione prima del ricaricamento con nginx -t o apachectl configtest. Come attivare attivamente tramite header la protezione dei visitatori, ad esempio con HSTS o una Content-Security-Policy, lo descrive la guida Header di sicurezza per i siti web.
Come verificare il risultato dall'esterno
Dopo il passaggio verifichi ogni dominio singolarmente, possibilmente anche una pagina di errore. I comandi seguenti inviano solo normali richieste ai Suoi siti:
# Header della home page
curl -sI https://www.example.de/ | grep -iE '^(server|x-powered-by):'
# Header di una pagina inesistente
curl -sI https://www.example.de/gibt-es-nicht-4711 | grep -iE '^(server|x-powered-by):'
Ci si aspetta un header Server senza numero di versione e nessun X-Powered-By. Se compare ancora una versione di PHP, di solito è attivo un altro php.ini o un servizio non è ancora stato riavviato. Se davanti al server c'è una CDN, verifichi inoltre direttamente il server di origine, se raggiungibile.
Registri comunque la versione di PHP internamente: nel Suo inventario dei server, con stato dei pacchetti e data dell'ultima verifica. Il livello di patch lo dimostra tramite il server, come descritto in Verificare correttamente versione di PHP e livello di patch.
Che cosa ottiene il nascondere e che cosa no
Valutato con onestà, disattivare le indicazioni di versione è una misura piccola e di poco sforzo. Riduce la probabilità di comparire in ricerche mirate di determinate versioni e diminuisce le informazioni che un aggressore ottiene senza fatica.
Non protegge però dagli attacchi automatizzati che inviano semplicemente le loro richieste a ogni server raggiungibile. Come si svolgono queste scansioni di massa lo descrive l'articolo Scansioni di massa alla ricerca di PHP senza patch. Contro PHP2Shell aiuta solo l'aggiornamento a PHP 8.5.12, 8.4.27, 8.3.36 o 8.2.35, oppure un backport confermato, seguito dal riavvio di tutti i processi PHP.
Un effetto collaterale è invece decisamente utile: chi disattiva verso l'esterno le indicazioni di versione deve rilevare le proprie versioni internamente in modo ordinato. In una situazione come PHP2Shell, proprio questo quadro decide quanto in fretta sa quali server sono interessati.
Il nascondere ha quindi senso come parte di un hardening di base, non come misura isolata. Rientra nella stessa checklist di output di errore disattivati, file di prova cancellati e valori di configurazione bloccati.
Come aiuta PHP SOS in concreto?
- Rilevare i punti: verifichiamo header, pagine di errore e webroot di tutti i domini alla ricerca di indicazioni di versione e file di prova dimenticati.
- Adattare la configurazione: impostiamo
expose_php, header Server e filtri di header in ogni versione di PHP e ogni server web e riavviamo in modo controllato i servizi. - Dimostrare internamente il livello di patch: documentiamo versioni e stato dei pacchetti dove devono stare, nell'inventario invece che nell'header HTTP.
- Integrare nell'hardening: la misura fa parte del nostro hardening del server per server web PHP.
Domande frequenti
expose_php = Off rende sicuro il mio server?
No. L'impostazione rimuove solo l'indicazione di versione dall'header HTTP. Una versione vulnerabile di PHP resta vulnerabile, e gli attacchi automatizzati provano comunque spesso le loro richieste su ogni server raggiungibile. Toglie però agli aggressori una semplice preselezione e riduce la visibilità nei motori di ricerca per server.
Posso impostare expose_php nel pool FPM o tramite .htaccess?
Secondo il manuale PHP, expose_php è modificabile solo in php.ini. Imposti quindi il valore nel php.ini di ogni SAPI web e riavvii poi PHP-FPM o Apache.
Perché vedo X-Powered-By nonostante expose_php = Off?
Di solito allora è l'applicazione o un framework a impostare l'header, oppure è attivo un altro php.ini. Rimuova l'header anche nel server web: con fastcgi_hide_header in Nginx o Header unset in Apache.
Come verifico il livello di patch se la versione non è più visibile?
Tramite il server stesso: gestione dei pacchetti, changelog dei pacchetti con i numeri CVE e ora di avvio dei processi PHP. L'indicazione nell'header HTTP non era comunque una prova, perché le distribuzioni applicano spesso backport senza un nuovo numero di versione.