Situazione attuale: PHP2Shell. Due vulnerabilità critiche di PHP (CVSS 9,2) consentono codice dannoso senza autenticazione. Patch dal 21/10/2026.Che cosa fare ora →

Isolare i pool PHP-FPM per ogni sito

Un pool dedicato per ogni sito è l'inizio, non la fine. Come verificare i pool esistenti e rafforzare socket, estensioni, pagine di stato, risorse e log.

Stato 6 min di letturaHardening e configurazione

In breve: ogni sito su un server dovrebbe avere un proprio pool PHP-FPM con un proprio utente di sistema e un proprio socket. La separazione diventa efficace però solo con i dettagli: permessi del socket solo per il server web, security.limit_extensions su .php, nessuna pagina di stato raggiungibile pubblicamente, limiti propri per processi e durata e log separati. Da PHP2Shell protegge solo l'aggiornamento; i pool limitano fin dove arriva un attacco.

Un server, molti siti, un rischio comune

Su molti server nel corso degli anni è cresciuto ciò che nessuno aveva pianificato così. Il sito aziendale, lo shop, una pagina di campagna del 2019 e un sistema di test girano affiancati, spesso con lo stesso utente e nello stesso pool. Se viene compromessa la pagina di campagna dimenticata, sono esposti anche i dati dei clienti dello shop.

PHP-FPM, il gestore di processi FastCGI di PHP, risolve il problema con i pool: gruppi di processi worker con impostazioni proprie. Come funziona il principio di base lo spiega PHP-FPM spiegato: gestore di processi, pool e worker. La costruzione di pool separati con utente proprio, cartella temporanea propria e open_basedir è descritta nella guida open_basedir e isolamento per sito. Questo articolo fa un passo in più: come verificare i pool esistenti e quali impostazioni rendono affidabile la separazione?

Importante per l'inquadramento: con PHP2Shell le vulnerabilità CVE-2026-109618 e CVE-2026-109619 si trovano nell'interprete PHP, condiviso da tutti i pool di una versione di PHP. Un pool dedicato non impedisce lo sfruttamento. Decide però se, dopo, un aggressore raggiunge un sito o tutti.

Pool PHP-FPM con utente dedicato: verificare lo stato attuale

Prima di cambiare qualcosa, si faccia un quadro generale. I comandi seguenti leggono soltanto. Percorsi e numeri di versione variano secondo la distribuzione:

# Tutti i pool con utente e socket
grep -HE '^\s*(\[|user|group|listen)\s*' /etc/php/*/fpm/pool.d/*.conf

# Pool in esecuzione e loro utenti
ps -eo user,pid,cmd | grep '[p]hp-fpm: pool'

# Socket e relativi permessi
ls -l /run/php/

# Verificare la configurazione alla ricerca di errori (non modifica nulla)
sudo php-fpm8.3 -t

Faccia attenzione a tre schemi: più siti nello stesso pool, pool che girano come www-data o addirittura come root, e socket scrivibili da tutti gli utenti. Ciascuno di essi mina la separazione.

Se sul server girano più versioni di PHP, ognuna ha il proprio servizio FPM con directory dei pool proprie. Le verifichi tutte, non solo la versione configurata per ultima. Proprio le versioni vecchie con pool dimenticati sono un rischio, perché spesso non vengono né curate né riavviate dopo gli aggiornamenti. Indicazioni in proposito si trovano in Più versioni di PHP su un server. Annoti il risultato in una piccola tabella: sito, pool, utente, socket, versione di PHP. Questo quadro è anche la base di ogni modifica successiva.

Le impostazioni più importanti per pool

Il prospetto seguente si basa sulla configurazione di FPM nel manuale PHP. I valori per processi e tempi dipendono dal Suo carico e dall'applicazione:

Impostazione Scopo Raccomandazione
user, group utente dei worker utente dedicato per sito, mai root
listen.owner, listen.group, listen.mode permessi sul socket solo gruppo del server web, modalità 0660
listen.acl_users accesso tramite ACL invece del proprietario inserire solo l'utente del server web
security.limit_extensions estensioni eseguibili limitare a .php (predefinito .php .phar)
clear_env svuotare le variabili d'ambiente lasciare al valore predefinito yes
pm.max_children numero massimo di worker limitare in modo che un sito non saturi il server
request_terminate_timeout interruzione di richieste bloccate impostare in base alla richiesta legittima più lunga
pm.status_path, ping.path pagina di stato e di ping impostare solo se necessario e proteggere internamente
slowlog, request_slowlog_timeout registro delle richieste lente un file proprio per ogni pool

Un estratto per un pool rafforzato si presenta così:

; /etc/php/8.3/fpm/pool.d/shop.conf (estratto)
[shop]
user = shop
group = shop
listen = /run/php/shop.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
request_terminate_timeout = 60s

security.limit_extensions = .php
clear_env = yes

slowlog = /var/log/php/shop.slow.log
request_slowlog_timeout = 10s
php_admin_value[error_log] = /var/log/php/shop.error.log

Impostazioni come memory_limit o session.upload_progress.enabled le definisca per pool con php_admin_value e php_admin_flag. Secondo il manuale, questi valori non si possono sovrascrivere con ini_set(). Maggiori informazioni in php_admin_value: bloccare le impostazioni contro la sovrascrittura.

Inquadrare correttamente pagine di stato e rotazione dei worker

pm.status_path e ping.path sono attivi solo se impostati. La pagina di stato mostra richieste in corso, processi e carico. Per il monitoraggio è utile, ma se raggiungibile pubblicamente è una fonte di informazioni superflua per gli aggressori. Inoltri questi percorsi nel server web solo per indirizzi interni. Come collaborano in modo sicuro Nginx e PHP-FPM lo descrive Mettere in sicurezza Nginx con PHP-FPM.

pm.max_requests stabilisce dopo quante richieste un worker si riavvia; il valore predefinito è 0, cioè mai. Un valore maggiore di zero aiuta contro un consumo di memoria che cresce lentamente. Non è pensato come protezione contro PHP2Shell: php.net non lo cita tra le misure transitorie e sottolinea che solo l'aggiornamento protegge completamente. Dopo l'aggiornamento vale inoltre: tutti i worker di tutti i pool devono essere riavviati, perché altrimenti i vecchi processi continuano a girare con il codice vulnerabile.

Consiglio

Mantenga un modello per i nuovi pool e crei ogni nuovo sito con esso. Così la separazione nasce in automatico, invece di essere aggiunta anni dopo.

Errori tipici durante il passaggio

L'errore più frequente è un nuovo pool che gira sì con un utente proprio, ma i cui file appartengono ancora a www-data. Allora il pool non può scrivere dove deve, e qualcuno imposta i permessi in modo troppo generoso. Chiarisca prima quali cartelle devono essere scrivibili. Il secondo errore sono le attività pianificate che continuano a girare con il vecchio utente e creano file con proprietario sbagliato. Il terzo è una cartella di sessione comune a tutti i pool, che annulla di nuovo la separazione.

Dopo ogni passaggio testi login, upload, cache e attività pianificate del sito e osservi il log degli errori del pool.

Come aiuta PHP SOS in concreto?

  • Rileviamo tutti i pool, utenti, socket e impostazioni e mostriamo dove oggi i siti condividono processi o permessi.
  • Configuriamo per ogni sito un pool rafforzato, con permessi del socket, limite delle estensioni, limiti di risorse e log propri.
  • Mettiamo in sicurezza le pagine di stato, riavviamo in modo controllato tutti i worker e testiamo ogni sito.
  • Nell'ambito dell'hardening del server documentiamo la separazione come modello per i progetti futuri.

Domande frequenti

Perché ogni sito dovrebbe avere un proprio pool PHP-FPM?

Un pool dedicato con un proprio utente di sistema separa i siti a livello di processi e di permessi sui file. Se un sito viene compromesso, il codice non può leggere senza difficoltà i file degli altri. Inoltre limiti e impostazioni si possono definire separatamente per ogni sito.

Un pool dedicato protegge da PHP2Shell?

No. Le vulnerabilità si trovano nell'interprete PHP stesso, che tutti i pool usano in comune. Protegge solo l'aggiornamento a una versione corretta con riavvio di tutti i worker. Pool separati limitano però fin dove arriva un attacco riuscito.

Che cosa ottiene security.limit_extensions?

Secondo il manuale PHP, l'impostazione limita quali estensioni di file PHP-FPM esegue come script principale. Il valore predefinito è .php e .phar. Limitarla a .php impedisce, ad esempio, che file immagine caricati vengano eseguiti come PHP, se il server web è configurato male.

La pagina di stato di PHP-FPM è pericolosa?

Rivela dettagli su processi e richieste in corso. Se è raggiungibile pubblicamente senza protezione, facilita l'orientamento degli aggressori. Secondo il manuale è attiva solo se pm.status_path è impostato. In tal caso il server web dovrebbe limitare il percorso agli indirizzi interni.

Fonti

Contatto immediato

Ogni ora conta. Ci scriva adesso.

Descriva brevemente sistema, versione di PHP e quanto osservato. Ci faremo sentire, chiariremo la situazione e lavoreremo da remoto fino alla chiusura e alla documentazione dell'incidente.

Aiuto immediato