Mitigare una vulnerabilità di PHP prima della patch: estensioni, SAPI e configurazione

Quali mitigazioni funzionano davvero in attesa della correzione di una CVE di PHP: estensioni da disattivare, configurazione di PHP-FPM e del server web, direttive del php.ini, filtri e accessi, con i loro limiti e il modo per verificarle.

Copertina con il logo php∞, la categoria Sicurezza e CVE, il titolo Mitigare prima della patch e il numero 13

Tra la pubblicazione di una vulnerabilità di PHP e l’installazione del pacchetto corretto passa sempre del tempo. Su un ramo supportato sono di solito pochi giorni, il tempo che la distribuzione o il repository pubblichino l’aggiornamento. Su un ramo fuori supporto il tempo dipende da quando arriva un backport o da quando si completa la migrazione. In quella finestra il server resta esposto, a meno di ridurre la superficie di attacco con le mitigazioni.

In questo articolo vediamo quali mitigazioni sono davvero utili per una vulnerabilità di PHP, organizzate per livello: estensioni, SAPI e server web, configurazione dell’interprete, filtri e accessi davanti all’applicazione. Per ognuna diciamo cosa blocca, cosa lascia aperto e come verificare che funzioni. Una premessa vale per tutto l’articolo: una mitigazione riduce il rischio in attesa della correzione e non la sostituisce.

Prima di tutto: dove si trova la falla

La mitigazione giusta dipende dalla parte di PHP in cui si trova il difetto. Gli avvisi di sicurezza e le schede su NVD lo indicano quasi sempre, e conviene leggerli con questa domanda in mente. Le vulnerabilità di PHP ricadono in poche famiglie:

  • in un’estensione, come la CVE-2023-3824 nella lettura degli archivi phar o la CVE-2022-31626 nel driver pdo_mysql con mysqlnd;
  • in una SAPI, come la CVE-2019-11043 di PHP-FPM con nginx o la CVE-2024-4577 di PHP-CGI su Windows;
  • nel nucleo dell’interprete, per esempio nella gestione delle richieste multipart, dei cookie o delle stringhe;
  • in una libreria esterna usata da PHP, come OpenSSL o libxml2, che segue gli aggiornamenti del sistema operativo.

Una falla in un’estensione si mitiga bene, quella nel nucleo molto meno. Lo schema qui sotto riassume quale leva usare in ciascun caso.

Tabella visiva che associa il tipo di vulnerabilità di PHP alla mitigazione più efficace. Falla in un’estensione non usata, come phar o un driver di database: disattivare l’estensione, efficacia alta. Falla in una SAPI o nel passaggio delle richieste, come PHP-FPM con nginx o PHP-CGI: modificare la configurazione del server web o cambiare SAPI, efficacia alta se la condizione è nota. Falla nel parsing di input, come richieste multipart, cookie o dati serializzati: limiti sulle dimensioni e regole del firewall applicativo, efficacia parziale. Falla nel nucleo dell’interprete raggiungibile da qualunque script: solo accessi ristretti e isolamento, efficacia bassa, serve la correzione. In ogni riga la mitigazione riduce il rischio ma il codice vulnerabile resta
Più la falla è periferica, più la mitigazione è efficace. Quando è nel nucleo, serve la correzione.

Estensioni: disattivare quello che non serve

È la mitigazione più efficace, perché toglie del tutto il codice vulnerabile dal processo. Molte installazioni caricano decine di estensioni installate anni fa e mai usate. Se la vulnerabilità riguarda una di queste, disattivarla chiude il problema fino alla correzione e spesso anche dopo.

# Estensioni caricate (CLI e PHP-FPM possono differire)
php -m
php-fpm -m 2>/dev/null

# Famiglia Red Hat: trova il file .ini che carica l'estensione
grep -l 'extension *= *phar' /etc/php.d/*.ini /etc/opt/remi/*/php.d/*.ini 2>/dev/null

# Debian e Ubuntu: disattiva il modulo per la SAPI fpm della versione 7.4
phpdismod -v 7.4 -s fpm phar
systemctl restart php7.4-fpm

Sulla famiglia Red Hat si commenta la riga extension= nel file trovato e si riavvia PHP-FPM. Prima di farlo bisogna cercare nel codice e nelle dipendenze se l’estensione viene usata: phar, per esempio, serve a Composer e ad alcune librerie che si distribuiscono come archivio. Se un’estensione è compilata dentro l’eseguibile anziché caricata come modulo, compare in php -m ma non ha un file .ini: in quel caso non si disattiva senza ricompilare.

Alcune falle si mitigano anche senza disattivare l’estensione. La CVE-2022-31626, per esempio, richiede che un utente possa indicare l’host e la password di una connessione al database: un’applicazione che usa solo credenziali fisse in configurazione non offre quella condizione, mentre uno strumento di installazione o di amministrazione dimenticato online sì. Rimuovere quegli script è una mitigazione a costo zero.

SAPI e server web

Molte vulnerabilità gravi dipendono dal modo in cui le richieste arrivano a PHP. In questi casi la configurazione del server web è la prima linea di difesa. Per la CVE-2019-11043 bastava che nginx verificasse l’esistenza dello script prima di passare la richiesta a PHP-FPM, oppure che non inviasse un PATH_INFO vuoto: ne parliamo nel dettaglio nell’articolo dedicato alla CVE-2019-11043.

Anche PHP-FPM offre alcune direttive utili, documentate nella pagina di configurazione di FPM su php.net:

  • security.limit_extensions limita le estensioni dei file che FPM accetta di eseguire; il valore predefinito è .php .phar, e restringerlo a .php evita che un errore di configurazione del server web faccia eseguire altri tipi di file;
  • clear_env, attivo per impostazione predefinita, impedisce che variabili d’ambiente arbitrarie arrivino ai processi;
  • user e group per pool permettono di eseguire ogni applicazione con un utente diverso, così una compromissione resta confinata ai file di quel sito.

Quando la falla è in una SAPI che non è indispensabile, la mitigazione più netta è smettere di usarla. Un PHP-CGI raggiungibile direttamente dal web, per esempio, è da sostituire con PHP-FPM. Le differenze di esposizione tra le SAPI sono il tema dell’articolo su PHP-FPM, mod_php e CGI.

Configurazione di PHP

Alcune direttive del php.ini limitano cosa può fare un attaccante che riesce a sfruttare una falla o a caricare uno script. Sono utili, purché se ne conoscano i limiti dichiarati dalla documentazione stessa.

; php.ini o file in /etc/php.d/ (Red Hat) o conf.d/ (Debian e Ubuntu)

; Funzioni che eseguono comandi di sistema: da provare con l'applicazione,
; alcune librerie le usano. La documentazione avverte che si possono aggirare.
disable_functions = exec,passthru,shell_exec,system,proc_open,popen

; Nessuna inclusione di codice da URL remoti (è già il valore predefinito)
allow_url_include = Off

; Limiti sulle richieste: riducono la superficie dei difetti nel parsing
post_max_size = 16M
upload_max_filesize = 8M
max_input_vars = 1000

; Non annuncia la versione nell'intestazione X-Powered-By
expose_php = Off

Due avvertenze. La documentazione delle direttive dice esplicitamente che disable_functions può essere aggirata e non va considerata una misura di sicurezza sufficiente. E la politica di sicurezza del progetto PHP non classifica come vulnerabilità un aggiramento di open_basedir: va considerato un confine utile contro gli errori di configurazione, inadatto a fermare un attaccante determinato. Quanto a expose_php = Off, nasconde la versione ma non corregge nulla; serve solo a non offrire l’informazione già pronta.

Davanti all’applicazione: filtri e accessi

L’ultimo livello agisce prima che la richiesta arrivi a PHP. Un firewall applicativo può bloccare le richieste che corrispondono alla firma di un exploit noto, ed è utile soprattutto quando l’attacco ha una forma riconoscibile, come un carattere particolare nel percorso o un’intestazione anomala. Il limite è che una firma blocca le varianti note: chi conosce la vulnerabilità può costruire una richiesta diversa con lo stesso effetto.

Più robusta è la restrizione degli accessi. Pannelli di amministrazione, strumenti di importazione, endpoint di servizio e vecchi script di installazione possono stare dietro una VPN, un elenco di indirizzi IP autorizzati o un’autenticazione del server web. Se la vulnerabilità richiede di raggiungere una di quelle funzioni, la restrizione la rende inaccessibile a chi sta fuori.

C’è poi l’isolamento del server nel suo complesso. Un server web che non ha bisogno di aprire connessioni verso Internet può avere il traffico in uscita bloccato dal firewall, a eccezione dei servizi necessari come il database, i repository dei pacchetti o le API dei fornitori. Se un attaccante riesce a eseguire codice, questa regola gli rende molto più difficile scaricare altri strumenti o inviare dati all’esterno. È una misura che non dipende dalla singola CVE e conviene mantenere anche dopo la correzione.

Schema a livelli delle mitigazioni per una vulnerabilità di PHP, dall’esterno verso l’interno. Rete e accessi: VPN, elenchi di IP autorizzati, autenticazione sulle aree amministrative. Server web e firewall applicativo: controllo di esistenza degli script, regole sulle richieste, limiti di dimensione. SAPI e pool di PHP-FPM: security.limit_extensions, clear_env, un utente per ogni pool. Configurazione di PHP: estensioni non usate disattivate, disable_functions, limiti su POST e upload. Al centro, il codice dell’interprete, dove solo la correzione con un aggiornamento o un backport elimina la vulnerabilità
Ogni livello toglie una parte di superficie di attacco; il difetto si chiude solo al centro.

Verificare che la mitigazione funzioni

Una mitigazione non verificata è un’ipotesi. Per ognuna serve una prova concreta, ripetibile anche da chi non l’ha applicata:

  1. per un’estensione disattivata, controllare che non compaia più nell’elenco dei moduli della SAPI usata dal sito, che può differire da quello della riga di comando;
  2. per una regola del server web, inviare una richiesta che dovrebbe essere bloccata e verificare la risposta, per esempio un 404 o un 403;
  3. per una direttiva di PHP, leggere il valore effettivo con una pagina temporanea che stampi ini_get(), da cancellare subito dopo;
  4. in ogni caso, provare i percorsi principali dell’applicazione e controllare i log per errori nuovi.

Ogni mitigazione va anche annotata, con data, motivo e CVE di riferimento. Dopo la correzione alcune vanno tolte, perché limitano funzioni utili; altre conviene tenerle, come la disattivazione delle estensioni inutili o la restrizione degli accessi amministrativi.

Quanto può durare una mitigazione

Il tempo che serve per arrivare alla correzione. Su un ramo supportato è l’attesa dell’aggiornamento. Su un ramo fuori supporto l’aggiornamento non arriva, e la mitigazione rischia di diventare permanente senza che nessuno l’abbia deciso. La strada per chiudere davvero la vulnerabilità è il backport della patch sul ramo in uso, che per un intervento d’urgenza su una singola CVE ha un obiettivo di 24 ore; la sequenza completa è descritta nell’articolo sulle prime 24 ore dopo una CVE critica.

Immaginiamo un portale su PHP 7.4 in cui, dopo una CVE in un’estensione, l’estensione è stata disattivata e tutto ha continuato a funzionare. È facile considerare chiusa la questione. Due anni dopo un nuovo plugin richiede proprio quell’estensione, qualcuno la riattiva per far funzionare il sito e la vulnerabilità torna aperta senza che nessuno se ne accorga. Una mitigazione senza scadenza e senza documentazione produce esattamente questo tipo di situazione.

Conclusioni

Mitigare una vulnerabilità di PHP prima della patch significa ridurre la superficie di attacco nella finestra che separa la pubblicazione della CVE dalla correzione. La scelta dipende da dove si trova la falla. Se è in un’estensione non usata, disattivarla è la misura più efficace. Se dipende dalla SAPI o dal server web, la configurazione di nginx, di Apache o dei pool di PHP-FPM può interrompere le condizioni dell’attacco. Le direttive del php.ini e i filtri davanti all’applicazione limitano i danni, con i limiti che la documentazione stessa dichiara. Ogni mitigazione va verificata, annotata e accompagnata da una data per la correzione: un aggiornamento sui rami supportati, un backport su quelli fuori supporto.

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 ↗