Kort sagt: Ved Nginx med PHP-FPM sidder sårbarheden fra PHP2Shell i PHP-FPM, ikke i Nginx. Patch alle PHP-FPM-versioner, genstart hver FPM-tjeneste fuldstændigt, og dokumenter det med processernes starttidspunkter. For Nginx PHP-FPM-sikkerheden på lang sigt tæller adskilte pools, værdier der ikke kan overskrives, og en Nginx-konfiguration, der ikke udfører uploadede filer.
Hvordan Nginx og PHP-FPM arbejder sammen
Nginx leverer statiske filer selv og sender forespørgsler til PHP-scripts videre til PHP-FPM via FastCGI. PHP-FPM består af en master-proces og flere worker-processer, grupperet i pools. En worker behandler mange forespørgsler efter hinanden.
Netop det er relevant for PHP2Shell. Ved CVE-2026-109619 kan en forespørgsels interne tilstand efter frigivelse af hukommelsen blive stående og udnyttes af en senere forespørgsel i samme worker. Ved CVE-2026-109618 kan en out-of-memory-tilstand afbryde PHP midt i initialiseringen af en forespørgsel. Begge sårbarheder er vurderet til CVSS v4.0 9,2 og rettet i PHP 8.5.12, 8.4.27, 8.3.36 og 8.2.35.
Kontrollér beholdningen: versioner, pools, processer
Mange servere har flere PHP-FPM-versioner side om side. Følgende kommandoer læser kun; pakke- og tjenestenavne er eksempler for Debian/Ubuntu og RHEL-familien.
# Hvilke FPM-tjenester kører?
systemctl list-units --type=service | grep -i fpm
# Hvilken version ligger bag? (eksempel Debian/Ubuntu)
php-fpm8.3 -v
# RHEL-familien
php-fpm -v
# Til hvilke sockets eller porte sender Nginx videre?
nginx -T 2>/dev/null | grep -E 'fastcgi_pass'
# Pools og deres brugere
grep -RhE '^\[|^user|^listen' /etc/php/*/fpm/pool.d/ 2>/dev/null
Afstem hver fastcgi_pass-post med en kørende pool. Så kan I se, hvilken PHP-version der betjener hvilket website. Ved distributionspakker er det ændringsloggen med CVE-numrene, der dokumenterer patchen, ikke versionsnummeret alene.
Et hyppigt fund ved sådanne optællinger er servere, hvor der gennem årene er installeret flere PHP-versioner, hvoraf kun én faktisk er i brug. De øvrige FPM-tjenester kører alligevel videre, ofte med standardpools, der lytter på en lokal socket eller port. De er udefra som regel ikke direkte tilgængelige, men er fortsat en unødig risiko og forlænger hver nødopdatering. Deaktivér og fjern versioner, som intet website bruger, efter at I har kontrolleret tildelingen via fastcgi_pass-posterne.
Ligeledes er det værd at se på poolenes bruger. Kører alle pools som www-data eller nginx, findes adskillelsen mellem websites kun på papiret. Den, der overtager ét website, kan så læse alle de andres filer, f.eks. konfigurationsfiler med databaseadgangskoder. Egne systembrugere pr. pool og passende filrettigheder skaber her en ægte grænse. Det er ingen afhjælpning af PHP2Shell, men begrænser tydeligt den mulige skade ved et vellykket angreb.
Indspil patchen og forny alle workere
Efter pakkeopdateringen genstarter I hver PHP-FPM-tjeneste. En reload erstatter nok workerne, men en fuldstændig genstart fornyer også master-processen og er efter sikkerhedsopdateringer den sikre vej.
# Eksempel Debian/Ubuntu, pr. installeret version
systemctl restart php8.3-fpm
# RHEL-familien
systemctl restart php-fpm
# Kontrol: starttidspunkt for master og workere
ps -eo pid,lstart,cmd | grep -E 'php-fpm' | grep -v grep
Hver proces skal være startet efter opdateringen. Udførligt beskrevet står det under Genstart PHP-FPM og alle workere.
En patch fjerner ikke skadelig software, som blev smuglet ind tidligere. Gem Nginx' adgangs- og fejlprotokoller fra og med 20.10.2026, og undersøg websites for spor.
Sæt midlertidige værdier i poolen
Så længe en version ikke er patchet, anbefaler php.net midlertidige foranstaltninger. De giver ikke fuldstændig beskyttelse. I PHP-FPM sætter I værdierne med php_admin_value henholdsvis php_admin_flag i poolen, så kan applikationer ikke overskrive dem via ini_set().
; Eksempel: /etc/php/8.3/fpm/pool.d/website.conf
php_admin_flag[session.upload_progress.enabled] = off
php_admin_value[post_max_size] = 32M
php_admin_value[upload_max_filesize] = 24M
Uden upload-funktion angiver php.net post_max_size = 8M. På PHP 8.5 kommer fatal_error_backtraces=0 til. Til anvisningen om memory_limit=-1 skal I bruge en hukommelsesgrænse på cgroup-niveau, f.eks. via MemoryMax i et systemd-tillæg til FPM-tjenesten. Tilpas i Nginx client_max_body_size til den nye post_max_size, så brugerne får forståelige fejlmeddelelser. Genstart derefter FPM.
Forbedr Nginx PHP-FPM-sikkerheden varigt
Ud over det akutte tilfælde hjælper nogle grundregler, som begrænser skaden ved fremtidige sårbarheder:
- Én pool pr. website med egen systembruger, egen socket og egen
open_basedir-grænse. Mere under open_basedir og isolation pr. website. - Socket-rettigheder sættes, så kun Nginx har adgang, og åbn ingen FPM-porte udad.
- Udfør kun eksisterende scripts: Sæt
try_files $uri =404;i PHP-location, så Nginx ikke sender stier videre til PHP, som ikke findes. - Udfør ikke uploads: Forbyd PHP-udførelse i upload-mapper. Henvisninger hertil står under Implementér filupload sikkert.
- Beskyt statussider: Gør
pm.status_pathogping.pathkun tilgængelige internt.
# Eksempel: ingen PHP-udførelse i upload-mappen
location ~* ^/uploads/.*\.php$ {
deny all;
}
Kontrollér hver ændring med nginx -t, før I genindlæser Nginx. Noter desuden, hvilke pools, versioner og særregler der findes på serveren. Denne korte dokumentation sparer værdifuld tid ved den næste kritiske sårbarhed, fordi ingen først skal lede efter, hvilket website der hænger på hvilken pool.
Hvordan hjælper PHP SOS konkret?
- Vi tildeler hvert website sin pool og PHP-version og kontrollerer den faktiske pakkestatus.
- Vi patcher, genstarter alle FPM-tjenester og dokumenterer processernes starttidspunkter som bevis.
- Indtil patchen er på plads, sætter vi de midlertidige værdier pr. pool og begrænser hukommelsen via cgroup.
- Som led i serverhærdningen adskiller vi pools, rettigheder og upload-mapper ordentligt.
- Ved mistanke om et indbrud overtager vi incident response.
Ofte stillede spørgsmål
Er systemctl reload nok for PHP-FPM efter en opdatering?
En reload fornyer workerne, men master-processen kan beholde den gamle kode. Efter en sikkerhedsopdatering er en fuldstændig genstart af tjenesten den sikre vej. Kontrollér bagefter starttidspunktet for master og workere.
Skal Nginx genstartes efter en PHP-opdatering?
Nginx indeholder selv ikke PHP og behøver ikke genstartes for PHP-patchen. Genstartes skal alle PHP-FPM-tjenester. Ændrer I samtidig Nginx-konfigurationen, så kontrollér den med nginx -t, før I genindlæser.
Hvorfor egne pools pr. website?
Hver pool kører med egen bruger og egne grænser. Bliver ét website kompromitteret, kommer angriberen ikke uden videre til de andres filer. Desuden kan midlertidige værdier sættes målrettet pr. pool.
Er pm.max_requests en beskyttelse mod PHP2Shell?
Nej, det erstatter ikke en patch. Værdien begrænser, hvor mange forespørgsler en worker behandler, før den erstattes. Det kan forkorte tilstandes levetid i processen, men er ikke en afhjælpning, som php.net nævner.