PHP-FPM, mod_php o CGI: come la SAPI cambia la tua esposizione alle vulnerabilità

mod_php, PHP-FPM e CGI a confronto dal punto di vista della sicurezza: come eseguono il codice, quanto isolano i siti, quali CVE reali hanno colpito ciascuna SAPI e come scoprire quale usa il tuo server.

Copertina con il logo php∞, la categoria Sicurezza e CVE, il titolo PHP-FPM, mod_php o CGI e il numero 14

Quando esce una vulnerabilità di PHP, una delle prime righe dell’avviso dice spesso in quale contesto è sfruttabile: «con PHP-FPM», «quando PHP è usato come CGI», «con Apache e PHP-CGI su Windows». Quel contesto è la SAPI, l’interfaccia con cui PHP riceve le richieste dal server web. Due server con la stessa versione di PHP possono avere un’esposizione molto diversa solo perché usano una SAPI diversa.

In questo articolo mettiamo a confronto le tre SAPI che si incontrano sui server web, mod_php, PHP-FPM e CGI, dal punto di vista della sicurezza: come eseguono il codice, quanto isolano i siti tra loro e quali vulnerabilità reali hanno colpito ciascuna. Chiudiamo con i comandi per capire quale SAPI usi e con cosa cambia per chi ha un PHP fuori supporto.

Cos’è una SAPI e perché conta

PHP è diviso in due parti: il motore che esegue il codice e le estensioni, comuni a tutte le installazioni, e la SAPI, lo strato che collega il motore al mondo esterno. La costante PHP_SAPI e la funzione php_sapi_name() restituiscono il nome della SAPI in uso. I valori più comuni, elencati nella documentazione di php.net, sono apache2handler per mod_php, fpm-fcgi per PHP-FPM, cgi-fcgi per PHP-CGI e cli per la riga di comando.

Per la sicurezza la SAPI conta in due modi. Il primo è diretto: ogni SAPI ha il proprio codice, e le vulnerabilità in quel codice riguardano solo chi la usa. Il secondo è indiretto: la SAPI decide con quale utente gira PHP e quanto i siti ospitati sullo stesso server sono separati tra loro, quindi decide quanto danno può fare una vulnerabilità sfruttata con successo.

Tre schemi affiancati delle SAPI di PHP. mod_php: PHP è caricato dentro ogni processo di Apache, con l’MPM prefork, e tutti i siti girano con lo stesso utente del server web, per esempio www-data o apache. PHP-FPM: nginx o Apache inoltrano le richieste via FastCGI a un socket; un processo master gestisce più pool, ciascuno con il proprio utente, per esempio sito1 e sito2, e la propria configurazione. CGI: il server web avvia l’eseguibile php-cgi per le richieste, direttamente o tramite un gestore FastCGI come mod_fcgid; la sicurezza dipende molto dalla configurazione e dal fatto che php-cgi non sia raggiungibile direttamente. Sotto ogni schema il livello di isolamento tra i siti: basso per mod_php, alto per PHP-FPM con un pool per sito, variabile per CGI
Tre modi di eseguire PHP, tre livelli di separazione tra i siti dello stesso server.

mod_php: PHP dentro Apache

Con mod_php l’interprete è un modulo caricato in ogni processo di Apache. È la configurazione storica, semplice da installare, e permette di impostare le direttive di PHP nei file .htaccess. Il manuale di PHP oggi la sconsiglia per le nuove installazioni e raccomanda PHP-FPM con mod_proxy_fcgi; ricorda anche che, se PHP non è compilato in modalità thread safe, mod_php richiede l’MPM prefork.

Dal punto di vista della sicurezza il limite principale è l’utente. Come spiega la pagina del manuale sulla sicurezza con Apache, PHP eredita i permessi dell’utente di Apache. Tutti i siti del server girano con lo stesso utente, quindi uno script compromesso su un sito può leggere i file di configurazione, e le password del database, di tutti gli altri. Su un server con un solo sito il problema è minore; su un server condiviso tra più applicazioni è il punto debole più serio.

PHP-FPM: processi separati e pool

PHP-FPM, incluso in PHP dalla versione 5.3.3, è un servizio autonomo che riceve le richieste via FastCGI da nginx o da Apache. Un processo master gestisce uno o più pool di processi, e ogni pool ha la propria configurazione: utente e gruppo, socket di ascolto e relativi permessi, limiti di memoria e di tempo, direttive di PHP impostate con php_admin_value che gli script non possono modificare.

Con un pool per ogni applicazione e un utente diverso per ciascuno, la compromissione di un sito resta confinata ai suoi file. PHP-FPM aggiunge poi controlli propri, come security.limit_extensions, che limita le estensioni dei file eseguibili, e clear_env, che ripulisce le variabili d’ambiente dei processi. Il rovescio della medaglia è che anche PHP-FPM ha il suo codice e le sue vulnerabilità, e che il passaggio dei parametri tra server web e FPM introduce una superficie in più, come ha dimostrato la CVE-2019-11043.

CGI e FastCGI: php-cgi

Con la SAPI CGI il server web esegue il programma php-cgi, una volta per richiesta nel CGI classico oppure tramite un gestore che tiene vivi i processi, come mod_fcgid per Apache. Combinata con meccanismi come suEXEC, permette di eseguire ogni sito con il proprio utente, e per questo è stata a lungo usata negli hosting condivisi.

È anche la SAPI con la storia di sicurezza più delicata, perché php-cgi nasce come programma da riga di comando e interpreta delle opzioni. Il manuale dedica un capitolo agli attacchi possibili con PHP installato come CGI e alla direttiva cgi.force_redirect. Due delle vulnerabilità più gravi della storia di PHP riguardano proprio questa SAPI, ed entrambe sono nel catalogo CISA delle vulnerabilità sfruttate.

Le vulnerabilità legate alla SAPI

Alcuni esempi reali mostrano quanto la SAPI determini l’esposizione. Le versioni affette sono quelle indicate da NVD, che elenca solo i rami allora supportati:

  • CVE-2012-1823, CGI: php-cgi interpretava come opzioni della riga di comando alcune query string senza il segno uguale, permettendo di eseguire codice. Affette le versioni precedenti alla 5.3.12 e le 5.4.x precedenti alla 5.4.2;
  • CVE-2019-11043, FPM: con nginx e una certa configurazione di fastcgi_split_path_info, una scrittura fuori dal buffer permetteva l’esecuzione di codice. Corretta nelle 7.1.33, 7.2.24 e 7.3.11;
  • CVE-2021-21703, FPM: un processo di un pool, che gira con un utente non privilegiato, poteva scrivere nella memoria condivisa con il master in esecuzione come root, e ottenere i privilegi di root. Corretta nelle 7.3.32, 7.4.25 e 8.0.12;
  • CVE-2024-4577, CGI su Windows: con Apache e PHP-CGI e alcune code page di Windows, la conversione dei caratteri permetteva di passare opzioni a php-cgi. Corretta nelle 8.1.29, 8.2.20 e 8.3.8.
Linea del tempo di quattro vulnerabilità di PHP legate alla SAPI. 2012, CVE-2012-1823, SAPI CGI: opzioni della riga di comando passate nella query string, affette le versioni precedenti alla 5.3.12 e le 5.4 precedenti alla 5.4.2, nel catalogo CISA delle vulnerabilità sfruttate. 2019, CVE-2019-11043, SAPI FPM con nginx: esecuzione di codice da remoto, corretta in 7.1.33, 7.2.24 e 7.3.11, nel catalogo CISA. 2021, CVE-2021-21703, SAPI FPM: escalation locale dei privilegi da un processo del pool a root, corretta in 7.3.32, 7.4.25 e 8.0.12. 2024, CVE-2024-4577, SAPI CGI su Windows: iniezione di opzioni tramite la conversione dei caratteri, corretta in 8.1.29, 8.2.20 e 8.3.8, nel catalogo CISA. Nota: chi usa mod_php non era esposto a nessuna delle quattro
Quattro CVE, quattro casi in cui la SAPI decide se una versione vulnerabile è anche sfruttabile.

Questo elenco va letto con attenzione. Ogni SAPI ha la propria superficie di attacco: mod_php ne ha meno nel passaggio delle richieste, ma offre un isolamento tra siti molto più debole, e le vulnerabilità del motore e delle estensioni colpiscono tutte le SAPI allo stesso modo.

Il confronto in sintesi

Aspettomod_phpPHP-FPMCGI / FastCGI
Dove gira PHPdentro i processi di Apacheservizio separato, pool di processiprocessi php-cgi avviati dal server web
Utentequello di Apache, uguale per tutti i sitiuno per pooluno per sito con suEXEC o simili
Isolamento tra sitibassoalto con un pool per sitovariabile, dipende dalla configurazione
Superficie specificaridottapassaggio dei parametri FastCGI, processo masterinterpretazione delle opzioni di php-cgi
Indicazione di php.netsconsigliato per le nuove installazioniraccomandato con Apache e nginxcon le cautele del capitolo sulla sicurezza CGI
Fonti: manuale di PHP su php.net, schede NVD delle CVE citate.

Come scoprire quale SAPI usi

Sullo stesso server possono convivere più SAPI, e la riga di comando usa sempre cli. Per sapere cosa esegue davvero il sito bisogna guardare il server web e i processi:

# Apache: è caricato mod_php o il proxy verso FastCGI?
apachectl -M 2>/dev/null | grep -Ei 'php|proxy_fcgi|fcgid'

# nginx: a quale socket o porta passa gli script PHP?
nginx -T 2>/dev/null | grep -n fastcgi_pass

# Processi PHP-FPM e php-cgi in esecuzione, con l'utente
ps -eo user,args | grep -E 'php-fpm|php-cgi' | grep -v grep

# Pool di PHP-FPM e utenti configurati (percorsi tipici)
grep -HE '^(user|group|listen) *=' /etc/php-fpm.d/*.conf /etc/php/*/fpm/pool.d/*.conf 2>/dev/null

Per una conferma definitiva basta uno script temporaneo nella cartella del sito che stampi PHP_SAPI, da cancellare subito dopo averlo aperto nel browser.

Cosa cambia con un PHP fuori supporto

Su un ramo fuori supporto la SAPI diventa una leva in più. Passare da mod_php a PHP-FPM è possibile anche su versioni vecchie, perché FPM esiste dalla 5.3.3, e non richiede di modificare il codice dell’applicazione. Richiede però attenzione ad alcuni dettagli: le direttive php_value e php_flag scritte nei file .htaccess non funzionano con FPM e vanno spostate nella configurazione del pool o in un file .user.ini, e i permessi dei file vanno rivisti per il nuovo utente.

Separare le applicazioni in pool con utenti diversi lascia intatte le vulnerabilità e limita il danno di quelle future. Sapere quale SAPI usa ogni server, invece, rende molto più rapido il triage della prossima CVE: molte domande dell’analisi riguardano proprio la SAPI. Le altre misure utili in attesa di una correzione sono descritte nell’articolo su come mitigare una vulnerabilità di PHP prima della patch, mentre per le correzioni vere e proprie su un ramo abbandonato il riferimento è il backport delle patch di sicurezza.

Tirando le somme

La SAPI è il modo in cui PHP riceve le richieste, e incide sulla sicurezza in due modi: ogni SAPI ha vulnerabilità proprie, e ognuna offre un diverso grado di isolamento tra i siti. mod_php esegue PHP dentro Apache con un solo utente per tutti i siti e oggi php.net lo sconsiglia per le nuove installazioni. PHP-FPM separa le applicazioni in pool con utenti distinti ed è la scelta raccomandata, con una superficie propria nel passaggio dei parametri FastCGI, come hanno mostrato la CVE-2019-11043 e la CVE-2021-21703. PHP-CGI ha la storia più delicata, dalla CVE-2012-1823 alla CVE-2024-4577. Sapere quale SAPI usa ogni server permette di capire in pochi minuti se una nuova CVE ti riguarda, e su un PHP fuori supporto il passaggio a PHP-FPM con un pool per applicazione riduce i danni delle vulnerabilità future.

IL PROSSIMO PASSO

Mettiamo
in sicurezza.

Indicaci versione di PHP, sistema operativo e cosa ti preoccupa. Ti risponderemo con una valutazione dell’esposizione e una proposta di intervento.

Richiedi supporto

Ti porta al modulo di richiesta, in quattro passi.

PHP LEGACY · MANAGED SERVER S.R.L.info@phplegacy.it +39 02 5656 9681

Lunedì – venerdì · 09:30 – 19:30

Urgenza in corso? Reperibilità H24
+39 340 985 4556 ↗