Aktuel situation: PHP2Shell. To kritiske PHP-sårbarheder (CVSS 9,2) tillader skadelig kode uden login. Rettelser siden 21.10.2026.Hvad der skal gøres nu →

Sådan sikrer I Nginx med PHP-FPM

Ved Nginx med PHP-FPM ligger sikkerheden i pools, rettigheder og en ren genstart. Sådan patcher I efter PHP2Shell og hærder Nginx og PHP-FPM varigt.

Status 5 min. læsetidServer & hosting

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.

Vigtigt

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_path og ping.path kun 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.

Kilder

Akut kontakt

Hver time tæller. Skriv til os nu.

Beskriv kort system, PHP-version og observation. Vi vender tilbage, afklarer situationen og arbejder på afstand, indtil hændelsen er afsluttet og dokumenteret.

Akut hjælp