Накратко: При Nginx с PHP-FPM уязвимостите от PHP2Shell са в PHP-FPM, а не в Nginx. Пачнете всички версии на PHP-FPM, рестартирайте изцяло всяка FPM услуга и го докажете с времената на стартиране на процесите. За трайната сигурност на Nginx и PHP-FPM значение имат отделните пулове, стойностите, които не могат да се презаписват, и конфигурация на Nginx, която не изпълнява качени файлове.
Как Nginx и PHP-FPM работят заедно
Nginx сервира статичните файлове сам, а заявките към PHP скриптове предава през FastCGI на PHP-FPM. PHP-FPM се състои от главен процес и няколко работни процеса, групирани в пулове. Един работен процес обработва последователно много заявки.
Точно това е важно за PHP2Shell. При CVE-2026-109619 вътрешно състояние на дадена заявка може да остане след освобождаване на паметта и да бъде използвано от по-късна заявка в същия работен процес. При CVE-2026-109618 състояние на недостиг на памет може да прекъсне PHP по средата на инициализирането на заявка. И двете уязвимости са оценени с CVSS v4.0 9,2 и са отстранени в PHP 8.5.12, 8.4.27, 8.3.36 и 8.2.35.
Проверка на наличното: версии, пулове, процеси
Много сървъри имат паралелно няколко версии на PHP-FPM. Следващите команди само четат; имената на пакетите и услугите са примери за Debian/Ubuntu и семейството RHEL.
# Кои FPM услуги работят?
systemctl list-units --type=service | grep -i fpm
# Каква версия стои зад тях? (пример Debian/Ubuntu)
php-fpm8.3 -v
# Семейство RHEL
php-fpm -v
# Към кои сокети или портове предава Nginx?
nginx -T 2>/dev/null | grep -E 'fastcgi_pass'
# Пулове и техните потребители
grep -RhE '^\[|^user|^listen' /etc/php/*/fpm/pool.d/ 2>/dev/null
Съпоставете всеки запис fastcgi_pass с работещ пул. Така виждате коя версия на PHP обслужва кой уебсайт. При пакети на дистрибуции пачът се доказва с дневника на промените с номерата на CVE, а не само с номера на версията.
Честа находка при такива описи са сървъри, на които през годините са инсталирани няколко версии на PHP, от които реално се ползва само една. Останалите FPM услуги въпреки това продължават да работят, често със стандартни пулове, които слушат на локален сокет или порт. Отвън те обикновено не са директно достъпни, но остават излишен риск и удължават всяка спешна актуализация. Деактивирайте и премахнете версиите, които никой уебсайт не ползва, след като проверите съответствието през записите fastcgi_pass.
Също така си струва да погледнете потребителя на пуловете. Ако всички пулове работят като www-data или nginx, разделението между уебсайтовете съществува само на хартия. Който овладее един уебсайт, може тогава да чете файловете на всички останали, например конфигурационни файлове с пароли за базата данни. Отделни системни потребители за всеки пул и подходящи права върху файловете създават тук истинска граница. Това не е мярка срещу PHP2Shell, но чувствително ограничава възможните щети от успешна атака.
Внесете пача и обновете всички работни процеси
След актуализацията на пакетите рестартирайте всяка PHP-FPM услуга. Презареждането заменя работните процеси, а пълният рестарт обновява и главния процес и след актуализации за сигурност е сигурният път.
# Пример Debian/Ubuntu, за всяка инсталирана версия
systemctl restart php8.3-fpm
# Семейство RHEL
systemctl restart php-fpm
# Проверка: време на стартиране на главния и на работните процеси
ps -eo pid,lstart,cmd | grep -E 'php-fpm' | grep -v grep
Всеки процес трябва да е стартиран след актуализацията. Подробно е описано в Рестартиране на PHP-FPM и на всички работни процеси.
Пачът не премахва зловреден софтуер, внесен преди това. Запазете протоколите за достъп и за грешки на Nginx от 20.10.2026 г. нататък и проверете уебсайтовете за следи.
Задаване на временни стойности в пула
Докато дадена версия не е пачната, php.net препоръчва временни мерки. Те не осигуряват пълна защита. В PHP-FPM задавате стойностите с php_admin_value, респективно php_admin_flag, в пула и тогава приложенията не могат да ги презапишат чрез ini_set().
; Пример: /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
Без функция за качване php.net посочва post_max_size = 8M. При PHP 8.5 се добавя fatal_error_backtraces=0. За указанието относно memory_limit=-1 Ви трябва ограничение на паметта на ниво cgroup, например чрез MemoryMax в допълнение към systemd за FPM услугата. Приведете в Nginx client_max_body_size към новия post_max_size, за да получават потребителите разбираеми съобщения за грешка. След това рестартирайте FPM.
Трайно подобряване на сигурността на Nginx и PHP-FPM
Отвъд острия случай помагат няколко основни правила, които ограничават щетите при бъдещи уязвимости:
- Един пул за всеки уебсайт със собствен системен потребител, собствен сокет и собствена граница
open_basedir. Повече в open_basedir и изолация за всеки уебсайт. - Права върху сокета така, че да има достъп само Nginx, без да се отварят FPM портове навън.
- Изпълнявайте само съществуващи скриптове: в PHP location задайте
try_files $uri =404;, за да не предава Nginx на PHP пътища, които не съществуват. - Не изпълнявайте качени файлове: забранете изпълнението на PHP в директориите за качване. Указания има в Сигурно реализиране на качване на файлове.
- Защитете страниците за състояние: направете
pm.status_pathиping.pathдостъпни само вътрешно.
# Пример: без изпълнение на PHP в директорията за качване
location ~* ^/uploads/.*\.php$ {
deny all;
}
Проверявайте всяка промяна с nginx -t, преди да презаредите Nginx. Записвайте и кои пулове, версии и специални правила съществуват на сървъра. Тази кратка документация спестява ценно време при следващата критична уязвимост, защото никой не трябва първо да търси кой уебсайт към кой пул принадлежи.
Как помага PHP SOS конкретно?
- Свързваме всеки уебсайт с неговия пул и версия на PHP и проверяваме действителното състояние на пакетите.
- Пачваме, рестартираме всички FPM услуги и документираме времената на стартиране на процесите като доказателство.
- До пача задаваме временните стойности за всеки пул и ограничаваме паметта чрез cgroup.
- В рамките на укрепването на сървъри разделяме чисто пуловете, правата и директориите за качване.
- При съмнение за проникване поемаме Incident Response.
Често задавани въпроси
Достатъчно ли е systemctl reload за PHP-FPM след актуализация?
Презареждането обновява работните процеси, но главният процес може да запази стария код. След актуализация за сигурност пълният рестарт на услугата е сигурният път. След това проверете времето на стартиране на главния и на работните процеси.
Трябва ли Nginx да се рестартира след актуализация на PHP?
Самият Nginx не съдържа PHP и не е нужно да се рестартира заради пача на PHP. Трябва да се рестартират всички PHP-FPM услуги. Ако при това променяте конфигурацията на Nginx, проверете я преди презареждане с nginx -t.
Защо отделни пулове за всеки уебсайт?
Всеки пул работи със собствен потребител и собствени ограничения. Ако един уебсайт бъде компрометиран, нападателят не достига лесно файловете на останалите. Освен това временните стойности могат да се задават целенасочено за всеки пул.
Защита срещу PHP2Shell ли е pm.max_requests?
Не, не замества пача. Стойността ограничава колко заявки обработва един работен процес, преди да бъде заменен. Това може да съкрати живота на състоянията в процеса, но не е мярка, посочена от php.net.