Aktuální situace: PHP2Shell. Dvě kritické zranitelnosti PHP (CVSS 9.2) umožňují spustit škodlivý kód bez přihlášení. Záplaty od 21. 10. 2026.Co nyní udělat →

Zabezpečení Nginx s PHP-FPM

U Nginx s PHP-FPM spočívá bezpečnost v poolech, oprávněních a čistém restartu. Takto po PHP2Shell záplatujete a trvale zpevníte Nginx i PHP-FPM.

Stav 4 min čteníServer a hosting

Stručně: U Nginx s PHP-FPM sídlí zranitelnost z PHP2Shell v PHP-FPM, nikoli v Nginx. Zazáplatujte všechny verze PHP-FPM, každou službu FPM úplně restartujte a doložte to časy spuštění procesů. Pro dlouhodobou bezpečnost Nginx a PHP-FPM mají význam oddělené pooly, hodnoty, které nelze přepsat, a konfigurace Nginx, která nespouští nahrané soubory.

Jak spolupracují Nginx a PHP-FPM

Nginx statické soubory obsluhuje sám a požadavky na skripty PHP předává přes FastCGI do PHP-FPM. PHP-FPM se skládá z hlavního procesu (master) a několika procesů workerů seskupených do poolů. Jeden worker zpracovává postupně mnoho požadavků.

Právě to je pro PHP2Shell podstatné. U CVE-2026-109619 může vnitřní stav požadavku po uvolnění paměti přetrvat a být využit pozdějším požadavkem ve stejném workeru. U CVE-2026-109618 může stav nedostatku paměti (out of memory) přerušit PHP uprostřed inicializace požadavku. Obě zranitelnosti jsou hodnoceny CVSS v4.0 9,2 a opraveny v PHP 8.5.12, 8.4.27, 8.3.36 a 8.2.35.

Zkontrolovat stav: verze, pooly, procesy

Na mnoha serverech běží vedle sebe několik verzí PHP-FPM. Následující příkazy jen čtou; názvy balíčků a služeb jsou příklady pro Debian/Ubuntu a rodinu RHEL.

# Které služby FPM běží?
systemctl list-units --type=service | grep -i fpm

# Jaká verze za tím stojí? (příklad Debian/Ubuntu)
php-fpm8.3 -v
# Rodina RHEL
php-fpm -v

# Na které sockety nebo porty Nginx předává?
nginx -T 2>/dev/null | grep -E 'fastcgi_pass'

# Pooly a jejich uživatelé
grep -RhE '^\[|^user|^listen' /etc/php/*/fpm/pool.d/ 2>/dev/null

Porovnejte každý záznam fastcgi_pass s běžícím poolem. Tak uvidíte, která verze PHP obsluhuje který web. U balíčků distribucí záplatu dokládá changelog s čísly CVE, nikoli samotné číslo verze.

Častým zjištěním při takové inventuře jsou servery, na kterých se během let nainstalovalo několik verzí PHP, z nichž se skutečně používá jen jedna. Ostatní služby FPM přesto běží dál, často se standardními pooly, které naslouchají na lokálním socketu nebo portu. Zvenčí bývají zpravidla přímo nedosažitelné, ale zůstávají zbytečným rizikem a prodlužují každou nouzovou aktualizaci. Verze, které žádný web nepoužívá, vypněte a odstraňte poté, co ověříte přiřazení pomocí záznamů fastcgi_pass.

Stejně tak se vyplatí pohled na uživatele poolů. Pokud všechny pooly běží jako www-data nebo nginx, je oddělení mezi weby jen na papíře. Kdo převezme jeden web, může pak číst soubory všech ostatních, například konfigurační soubory s hesly k databázi. Vlastní systémoví uživatelé pro každý pool a vhodná oprávnění k souborům tu vytvoří skutečnou hranici. Není to náprava pro PHP2Shell, ale výrazně to omezuje možné škody úspěšného útoku.

Nasadit záplatu a obnovit všechny workery

Po aktualizaci balíčků restartujte každou službu PHP-FPM. Reload sice workery nahradí, úplný restart ale obnoví i hlavní proces a po bezpečnostních aktualizacích je to bezpečná cesta.

# Příklad Debian/Ubuntu, pro každou nainstalovanou verzi
systemctl restart php8.3-fpm
# Rodina RHEL
systemctl restart php-fpm

# Kontrola: čas spuštění masteru a workerů
ps -eo pid,lstart,cmd | grep -E 'php-fpm' | grep -v grep

Každý proces musí být spuštěn po aktualizaci. Podrobně je to popsáno na stránce Restart PHP-FPM a všech workerů.

Důležité

Záplata neodstraní škodlivý software zavlečený dříve. Uchovejte přístupové a chybové logy Nginx od 20. 10. 2026 a zkontrolujte weby, zda nenesou stopy.

Nastavit přechodné hodnoty v poolu

Dokud verze není zazáplatována, doporučuje php.net přechodná opatření. Neposkytují úplnou ochranu. V PHP-FPM nastavíte hodnoty pomocí php_admin_value, resp. php_admin_flag v poolu, aplikace je pak nemohou přes ini_set() přepsat.

; Příklad: /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

Bez funkce nahrávání souborů uvádí php.net post_max_size = 8M. Na PHP 8.5 přibývá fatal_error_backtraces=0. Pro upozornění k memory_limit=-1 potřebujete limit paměti na úrovni cgroup, například pomocí MemoryMax v doplňku systemd pro službu FPM. V Nginx přizpůsobte client_max_body_size nové hodnotě post_max_size, aby uživatelé dostávali srozumitelné chybové hlášky. Poté FPM restartujte.

Trvale zlepšit bezpečnost Nginx a PHP-FPM

Nad rámec akutního případu pomáhá několik základních pravidel, která omezí škody při budoucích zranitelnostech:

  • Jeden pool pro každý web s vlastním systémovým uživatelem, vlastním socketem a vlastní hranicí open_basedir. Více na stránce open_basedir a izolace pro každý web.
  • Oprávnění socketu nastavit tak, aby se mohl připojit jen Nginx, žádné porty FPM neotevírat navenek.
  • Spouštět jen existující skripty: V location pro PHP nastavit try_files $uri =404;, aby Nginx nepředával PHP cesty, které neexistují.
  • Nespouštět nahrané soubory: V adresářích pro nahrávání zakázat spouštění PHP. Pokyny najdete na stránce Bezpečné nahrávání souborů.
  • Chránit stavové stránky: pm.status_path a ping.path zpřístupnit jen interně.
# Příklad: žádné spouštění PHP v adresáři pro nahrávání
location ~* ^/uploads/.*\.php$ {
    deny all;
}

Každou změnu zkontrolujte pomocí nginx -t, než Nginx znovu načtete. Zaznamenejte si také, jaké pooly, verze a zvláštní pravidla na serveru existují. Tato krátká dokumentace při příští kritické zranitelnosti ušetří cenný čas, protože nikdo nemusí nejprve hledat, který web patří ke kterému poolu.

Jak konkrétně pomáhá PHP SOS?

  • Přiřadíme každý web jeho poolu a verzi PHP a zkontrolujeme skutečný stav balíčků.
  • Zazáplatujeme, restartujeme všechny služby FPM a časy spuštění procesů zdokumentujeme jako doklad.
  • Do záplaty nastavíme přechodné hodnoty pro každý pool a omezíme paměť přes cgroup.
  • V rámci zpevnění serveru čistě oddělíme pooly, oprávnění a adresáře pro nahrávání.
  • Při podezření na průnik převezmeme reakci na incidenty.

Časté dotazy

Stačí po aktualizaci systemctl reload pro PHP-FPM?

Reload obnoví workery, hlavní proces (master) ale může starý kód zachovat. Po bezpečnostní aktualizaci je bezpečnou cestou úplný restart služby. Poté zkontrolujte čas spuštění masteru i workerů.

Musí se Nginx po aktualizaci PHP restartovat?

Samotný Nginx PHP neobsahuje a kvůli záplatě PHP se restartovat nemusí. Restartovat se musí všechny služby PHP-FPM. Pokud při tom měníte konfiguraci Nginx, před opětovným načtením ji zkontrolujte pomocí nginx -t.

Proč vlastní pooly pro každý web?

Každý pool běží s vlastním uživatelem a vlastními hranicemi. Pokud je jeden web kompromitován, útočník se bez dalšího nedostane k souborům ostatních. Přechodné hodnoty lze navíc nastavit cíleně pro každý pool.

Je pm.max_requests ochranou proti PHP2Shell?

Ne, záplatu nenahrazuje. Hodnota omezuje, kolik požadavků worker zpracuje, než je nahrazen. To může zkrátit životnost stavů v procesu, ale není to náprava uvedená php.net.

Zdroje

Okamžitý kontakt

Každá hodina se počítá. Napište nám hned.

Stručně popište systém, verzi PHP a pozorování. Ozveme se, vyjasníme situaci a budeme pracovat na dálku, dokud nebude incident uzavřen a zdokumentován.

Okamžitá pomoc