Backport delle patch di sicurezza: cos’è e come protegge una versione di PHP fuori supporto

Cosa significa portare una correzione scritta per PHP moderno su un ramo in End of Life, come lo fanno da sempre le distribuzioni Linux, come si costruisce e si verifica il pacchetto e cosa il backport non può fare.

Copertina con il logo php∞, la categoria Sicurezza e CVE, il titolo Backport delle patch di sicurezza e il numero 08

Quando esce una vulnerabilità grave di PHP, la raccomandazione ufficiale è sempre la stessa: aggiornare all’ultima versione del proprio ramo. Per chi usa PHP 5.6, 7.4 o 8.0 quella versione non esiste, perché il ramo non riceve più rilasci. Restano due possibilità immediate: migrare l’applicazione a un ramo supportato, che richiede settimane o mesi, oppure portare la correzione sul PHP che è già in produzione. Questa seconda strada si chiama backport.

In questo articolo spieghiamo cos’è il backport di una patch di sicurezza, perché le distribuzioni Linux lo usano da sempre, come si fa in pratica su un pacchetto PHP, come riconoscere un pacchetto corretto dal numero di versione e, soprattutto, cosa il backport non può fare. Usiamo come esempio una vulnerabilità reale, la CVE-2019-11043 di PHP-FPM.

Cosa significa fare il backport di una patch

Una correzione di sicurezza nasce sul codice dei rami supportati: gli sviluppatori di PHP scrivono la modifica, la verificano con un test e la pubblicano nel rilascio successivo. Fare il backport significa prendere quella stessa modifica e applicarla a una versione più vecchia del software, adattandola al codice che nel frattempo è cambiato. Il risultato è un PHP con lo stesso numero di versione di prima, le stesse funzioni e lo stesso comportamento, ma senza la falla.

La definizione più chiara è quella che Red Hat pubblica nella sua pagina sulla pratica del backporting: prendere la correzione di una falla dalla versione più recente di un pacchetto e applicarla alla versione più vecchia che si distribuisce. Red Hat descrive anche i tre passaggi del lavoro, cioè isolare la correzione dalle altre modifiche, verificare che non introduca effetti indesiderati e applicarla alle versioni già rilasciate.

Il vantaggio è evidente per chi gestisce un’applicazione che non può cambiare versione di PHP da un giorno all’altro. Il codice dell’applicazione non si tocca, le estensioni restano quelle, la configurazione pure. Cambia solo il binario dell’interprete, e cambia nel punto preciso in cui c’era il difetto.

Perché le distribuzioni lo fanno da sempre

Il backport non è una tecnica di nicchia. È il modo normale in cui Red Hat, Debian, Ubuntu e SUSE mantengono i pacchetti delle proprie release stabili. Una distribuzione promette di non cambiare il comportamento del sistema durante il suo ciclo di vita, e per mantenere la promessa non può sostituire PHP 7.4 con PHP 8.3 solo perché è uscita una CVE.

Red Hat racconta un caso proprio su PHP. Il ramo 5.3 ha raggiunto la fine del supporto il 14 agosto 2014; due mesi dopo è stata pubblicata la CVE-2014-3670, un buffer overflow presente in tutte le versioni di PHP. Il progetto PHP l’ha corretta nei rami ancora attivi, mentre Red Hat ha portato la correzione nel PHP 5.3 di Red Hat Enterprise Linux 6, perché i suoi clienti non potevano passare alla 5.4 senza adattare le applicazioni. Le domande frequenti sulla sicurezza di Debian spiegano la stessa scelta: cambiare versione introduce modifiche di comportamento, mentre il backport ne introduce il meno possibile.

Il limite di questo modello è temporale. La distribuzione corregge il suo PHP finché la release è supportata. Quando la release esce dal supporto, come è successo a CentOS 7 a giugno 2024, il PHP installato smette di ricevere correzioni insieme al resto del sistema. Lo stesso vale per i rami di PHP installati da repository di terze parti, che seguono le proprie regole.

Un esempio reale: la CVE-2019-11043

La CVE-2019-11043 riguarda PHP-FPM e, con alcune configurazioni di nginx, permette l’esecuzione di codice da remoto. Il progetto PHP l’ha corretta il 24 ottobre 2019 con i rilasci 7.1.33, 7.2.24 e 7.3.11. La correzione nel codice sorgente è minima: due righe del file sapi/fpm/fpm/fpm_main.c che aggiungono un controllo sulla lunghezza di PATH_INFO, più un nuovo test automatico che riproduce il caso.

Il codice difettoso però era presente anche nei rami precedenti, già fuori supporto. Per questo nelle settimane successive le distribuzioni hanno pubblicato pacchetti corretti per versioni che il progetto PHP non aggiornava più: PHP 5.3 e 5.4 su Red Hat Enterprise Linux 6 e 7, PHP 7.0 su Debian 9 e Ubuntu 16.04, PHP 5.5 su Ubuntu 14.04 con il supporto esteso. Tutti backport della stessa modifica.

Schema della correzione della CVE-2019-11043: a sinistra il commit del progetto PHP del 24 ottobre 2019, due righe in fpm_main.c più un test, pubblicato nei rilasci ufficiali 7.1.33, 7.2.24 e 7.3.11. A destra i backport delle distribuzioni sui rami già fuori supporto, con il pacchetto corretto: Red Hat Enterprise Linux 6 con PHP 5.3.3, Red Hat Enterprise Linux 7 con PHP 5.4.16, Debian 9 con PHP 7.0.33-0+deb9u6, Ubuntu 16.04 con PHP 7.0.33-0ubuntu0.16.04.7 e Ubuntu 14.04 ESM con PHP 5.5.9. In ogni caso la versione di PHP resta la stessa e cambia solo la parte del numero gestita dalla distribuzione
Una correzione, molti backport: la stessa modifica portata su rami che il progetto PHP non aggiornava più.

L’esempio mostra un punto importante. Chi aveva un PHP 7.0 di Debian 9 aggiornato era protetto, chi aveva lo stesso PHP 7.0 compilato a mano o installato da un repository non più mantenuto era esposto. Il numero di versione era identico.

Come si fa un backport, passo per passo

Per una singola correzione il lavoro segue sempre la stessa sequenza. È quella che usiamo nei nostri interventi, e ricalca quella delle distribuzioni.

Diagramma in sei passaggi del backport di una patch di sicurezza su PHP: 1, analisi della CVE e della correzione ufficiale nel ramo supportato; 2, verifica che il codice vulnerabile sia presente nel ramo in uso e raggiungibile con la configurazione del server; 3, adattamento della patch al codice vecchio; 4, ricostruzione del pacchetto RPM o DEB partendo da quello installato, con lo stesso numero di versione e un numero di release più alto; 5, test automatici di PHP e test dell’applicazione reale in un ambiente di prova; 6, rilascio in produzione con Ansible e piano di rollback. Sotto, la nota che il risultato è la stessa versione di PHP senza quella vulnerabilità
Le sei fasi di un backport: si parte dalla correzione ufficiale e si arriva a un pacchetto installabile al posto di quello in uso.

Analisi della vulnerabilità

Si parte dall’avviso ufficiale e dalla correzione pubblicata nel repository di PHP. La prima domanda è se il codice vulnerabile esiste nel ramo in uso: una funzione introdotta in PHP 8.1 non può avere una falla su PHP 5.6. La seconda è se quel codice è raggiungibile sul server: una vulnerabilità di PHP-FPM non riguarda chi usa mod_php, e una falla in un’estensione non caricata non è sfruttabile.

Adattamento della patch

Tra PHP 5.6 e PHP 8 l’interprete è stato in gran parte riscritto: strutture dati, gestione della memoria e API interne sono diverse. Una correzione di due righe sul ramo moderno può applicarsi quasi uguale a quello vecchio, oppure richiedere di capire come lo stesso controllo va scritto su un codice che lavora in modo diverso. È la parte che richiede esperienza sul codice sorgente di PHP, e la ragione per cui il backport non si automatizza.

Pacchetto, test e rilascio

La patch va inserita nel pacchetto che il server usa già, che sia di Remi, delle Software Collections, di AppStream, della distribuzione o di deb.sury.org. Ricostruire da quel pacchetto mantiene identici percorsi, file di configurazione ed estensioni, e permette di tornare indietro installando la versione precedente. Poi si eseguono i test automatici di PHP, compreso quello che riproduce la falla quando esiste, e si prova l’applicazione reale in un ambiente di prova. Solo a quel punto il pacchetto va in produzione, con Ansible e un piano di rollback già pronto.

Il numero di versione non cambia

Un PHP corretto con un backport si presenta con la stessa versione di prima. php -v continua a mostrare 5.4.16 o 7.0.33, e lo stesso numero compare nell’intestazione X-Powered-By se è attiva. Quello che cambia è la parte del numero gestita da chi mantiene il pacchetto: la release negli RPM, il suffisso nei pacchetti DEB. E il changelog del pacchetto elenca le CVE corrette.

# RPM: la versione resta 5.4.16, cambia il numero di release
# (esempio reale: php-fpm-5.4.16-46.1.el7_7 corregge la CVE-2019-11043)
rpm -q php-fpm
rpm -q --changelog php-fpm | grep -i cve | head -n 10

# DEB: la versione resta 7.0.33, il suffisso indica l'aggiornamento
# (esempio reale: 7.0.33-0+deb9u6 su Debian 9)
dpkg-query -W -f='${Version}\n' php7.0-fpm
zcat /usr/share/doc/php7.0-fpm/changelog.Debian.gz | grep -i cve | head -n 10

Questo comportamento ha una conseguenza pratica. Molti scanner di vulnerabilità leggono solo il numero di versione e segnalano come vulnerabile un PHP che in realtà è stato corretto. Red Hat lo scrive esplicitamente: gli strumenti che decidono solo in base alla versione producono falsi positivi. La risposta corretta a un report di questo tipo è mostrare il changelog del pacchetto con le CVE corrette.

Cosa il backport non può fare

Il backport chiude vulnerabilità specifiche e note. Ha limiti precisi, ed è bene conoscerli prima di sceglierlo:

  • non rende la versione supportata: ogni nuova CVE pubblicata sui rami moderni va valutata e, se riguarda il ramo in uso, corretta con un nuovo intervento;
  • non risolve la compatibilità: librerie Composer, SDK di pagamento e nuove versioni dei CMS continuano a richiedere PHP 8;
  • non sempre è possibile: quando una correzione richiede di riscrivere grandi porzioni di codice, anche Debian ammette che il backport può non essere praticabile;
  • non copre le librerie di sistema: OpenSSL, libxml2, ICU e le altre librerie usate da PHP seguono il sistema operativo, e se il sistema è fuori supporto vanno considerate a parte;
  • non corregge l’applicazione: una SQL injection nel codice del sito o una falla in un plugin non dipende dalla versione di PHP.

Il backport protegge la produzione oggi. La migrazione toglie il problema domani.

Quando conviene e come si inserisce in un piano

Il backport è la scelta giusta quando un’applicazione importante deve restare online e non può essere migrata nel tempo che una vulnerabilità concede. Immaginiamo un gestionale su PHP 5.6, con anni di codice personalizzato e integrazioni con altri sistemi: la migrazione a PHP 8 è un progetto di mesi, mentre una CVE grave su PHP-FPM chiede una risposta in giorni. Il backport copre quella distanza.

Sul solo PHP 5.6.40 il nostro pacchetto corregge 55 CVE, di cui 11 aggiunte da noi con backport dedicati; ne parliamo in dettaglio nell’articolo sulle CVE corrette su PHP 5.6.40. Il lavoro accumulato su quel ramo dà un’idea di quante correzioni servano per tenere al sicuro una versione abbandonata da anni. Per decidere tra le due strade quando una CVE colpisce un server in produzione, abbiamo dedicato un articolo a parte a backport o migrazione.

Se hai un PHP fuori supporto e vuoi sapere quali vulnerabilità pubblicate riguardano davvero la tua configurazione, è il punto da cui partono i nostri interventi di backport, sempre come ponte verso una migrazione pianificata.

In breve

Fare il backport di una patch di sicurezza significa portare la correzione scritta per i rami moderni di PHP sul ramo fuori supporto che l’applicazione usa, senza cambiare versione né comportamento. Le distribuzioni Linux lo fanno da sempre, come mostra la CVE-2019-11043, corretta da Red Hat, Debian e Ubuntu anche su PHP 5.3, 5.4, 5.5 e 7.0. Il lavoro richiede analisi della vulnerabilità, adattamento del codice, ricostruzione del pacchetto in uso, test con l’applicazione reale e un rilascio con rollback. Il numero di versione resta lo stesso, quindi le prove della correzione stanno nel changelog. Il backport chiude le falle note e dà tempo, ma non rende la versione supportata: funziona come ponte verso la migrazione.

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 ↗