Текуща ситуация: PHP2Shell. Две критични уязвимости в PHP (CVSS 9,2) позволяват злонамерен код без вход. Корекции от 21.10.2026 г.Какво да направите сега →

Изолиране на PHP-FPM пулове за всеки сайт

Отделен пул за всеки сайт е началото, не краят. Така проверявате съществуващите пулове и заздравявате сокетите, разширенията, статус страниците, ресурсите и логовете.

Актуалност 5 мин. четенеЗаздравяване и конфигурация

Накратко: Всеки сайт на един сървър трябва да има собствен PHP-FPM пул със собствен системен потребител и собствен сокет. Разделянето обаче действа истински едва с детайлите: права на сокета само за уеб сървъра, security.limit_extensions на .php, без публично достъпни статус страници, собствени лимити за процеси и време на изпълнение, както и отделни логове. От самия PHP2Shell защитава само актуализацията; пуловете ограничават докъде стига една атака.

Един сървър, много сайтове, общ риск

На много сървъри с годините е пораснало нещо, което никой не е планирал така. Фирменият уебсайт, магазинът, кампанийна страница от 2019 г. и тестова система работят един до друг, често под същия потребител и в същия пул. Ако забравената кампанийна страница бъде компрометирана, данните на клиентите на магазина също са изложени.

PHP-FPM, FastCGI мениджърът на процеси на PHP, решава това с пулове: групи от worker процеси със собствени настройки. Как работи основният принцип, обяснява PHP-FPM обяснен: мениджър на процеси, пулове и worker процеси. Изграждането на отделни пулове със собствен потребител, собствена временна папка и open_basedir описва ръководството open_basedir и изолация за всеки сайт. Тази статия отива една стъпка по-нататък: как да проверите съществуващите пулове и кои настройки правят разделянето устойчиво?

Важно за оценката: при PHP2Shell уязвимостите CVE-2026-109618 и CVE-2026-109619 са в интерпретатора на PHP, който всички пулове на една версия на PHP споделят. Собственият пул не предотвратява използването им. Той обаче решава дали нападателят след това достига един сайт или всички.

PHP-FPM пулове със собствен потребител: проверка на съществуващото

Преди да промените нещо, си създайте общ поглед. Следните команди само четат. Пътищата и номерата на версиите се различават според дистрибуцията:

# Всички пулове с потребител и сокет
grep -HE '^\s*(\[|user|group|listen)\s*' /etc/php/*/fpm/pool.d/*.conf

# Работещи пулове и техните потребители
ps -eo user,pid,cmd | grep '[p]hp-fpm: pool'

# Сокети и техните права
ls -l /run/php/

# Проверка на конфигурацията за грешки (не променя нищо)
sudo php-fpm8.3 -t

Обърнете внимание на три модела: няколко сайта в един и същ пул, пулове, които работят като www-data или дори като root, и сокети, в които могат да пишат всички потребители. Всеки от тях подкопава разделянето.

Ако на сървъра работят няколко версии на PHP, всяка има собствена FPM услуга със собствени директории за пулове. Проверете всички, не само версията, която сте настроили последно. Именно старите версии със забравени пулове са риск, защото често нито се поддържат, нито се рестартират след актуализации. Насоки по темата има в Няколко версии на PHP на един сървър. Запишете резултата в малка таблица: сайт, пул, потребител, сокет, версия на PHP. Този преглед е и основата за всяка по-късна промяна.

Най-важните настройки за всеки пул

Следният преглед се основава на конфигурацията на FPM в ръководството на PHP. Стойностите за процеси и времена зависят от Вашето натоварване и приложение:

Настройка Цел Препоръка
user, group потребител на worker процесите собствен потребител за всеки сайт, никога root
listen.owner, listen.group, listen.mode права върху сокета само групата на уеб сървъра, режим 0660
listen.acl_users достъп чрез ACL вместо собственик въведете само потребителя на уеб сървъра
security.limit_extensions изпълними разширения ограничете до .php (по подразбиране .php .phar)
clear_env изчистване на променливите на средата оставете стойността по подразбиране yes
pm.max_children максимален брой worker процеси ограничете така, че един сайт да не натоварва сървъра докрай
request_terminate_timeout прекъсване на увиснали заявки задайте според най-дългата легитимна заявка
pm.status_path, ping.path статус и ping страница задавайте само ако е нужно и ги защитете вътрешно
slowlog, request_slowlog_timeout протокол на бавните заявки за всеки пул в отделен файл

Откъс за заздравен пул изглежда така:

; /etc/php/8.3/fpm/pool.d/shop.conf (откъс)
[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

Настройки като memory_limit или session.upload_progress.enabled задавате за всеки пул с php_admin_value и php_admin_flag. Според ръководството тези стойности не могат да се презапишат с ini_set(). Повече по темата в php_admin_value: заключване на настройки срещу презаписване.

Правилно разбиране на статус страниците и смяната на worker процеси

pm.status_path и ping.path са активни само ако са зададени. Статус страницата показва работещите заявки, процеси и натоварване. За мониторинг това е полезно, но при публичен достъп е излишен източник на информация за атакуващите. Препращайте тези пътища в уеб сървъра само за вътрешни адреси. Как Nginx и PHP-FPM работят сигурно заедно, описва Защита на Nginx с PHP-FPM.

pm.max_requests определя след колко заявки един worker процес се стартира наново; по подразбиране е 0, тоест никога. Стойност над нула помага срещу бавно нарастващо потребление на памет. Като защита срещу PHP2Shell той не е предвиден: php.net не го посочва сред временните мерки и подчертава, че само актуализацията защитава изцяло. След актуализацията важи и следното: всички worker процеси на всички пулове трябва да се рестартират, защото иначе старите процеси продължават да работят с уязвимия код.

Съвет

Поддържайте шаблон за нови пулове и създавайте всеки нов сайт с него. Така разделянето възниква автоматично, вместо да се докарва години по-късно.

Типични грешки при прехода

Най-честата грешка е нов пул, който работи под собствен потребител, но чиито файлове продължават да принадлежат на www-data. Тогава пулът не може да пише там, където трябва, и някой задава правата твърде щедро. Изяснете предварително в кои папки трябва да може да се пише. Втората грешка са планирани задачи, които продължават да работят под стария потребител и създават файлове с неправилен собственик. Третата е обща папка за сесии за всички пулове, която отново премахва разделянето.

След всеки преход тествайте вход, качвания, кешове и планирани задачи на сайта и наблюдавайте лога за грешки на пула.

Как помага PHP SOS конкретно?

  • Отчитаме всички пулове, потребители, сокети и настройки и показваме къде днес сайтовете си делят процеси или права.
  • Създаваме за всеки сайт заздравен пул, с права на сокета, ограничение на разширенията, лимити на ресурсите и собствени логове.
  • Защитаваме статус страниците, рестартираме контролирано всички worker процеси и тестваме всеки сайт.
  • В рамките на заздравяването на сървъра документираме разделянето като шаблон за бъдещи проекти.

Често задавани въпроси

Защо всеки сайт трябва да има собствен PHP-FPM пул?

Собствен пул със собствен системен потребител разделя сайтовете на ниво процеси и права върху файловете. Ако един сайт бъде компрометиран, кодът не може лесно да чете файловете на останалите. Освен това лимитите и настройките могат да се определят отделно за всеки сайт.

Защитава ли собственият пул от PHP2Shell?

Не. Уязвимостите са в самия интерпретатор на PHP, който всички пулове използват съвместно. Защита дава само актуализацията до коригирана версия с рестартиране на всички worker процеси. Отделните пулове обаче ограничават докъде стига една успешна атака.

Какво прави security.limit_extensions?

Според ръководството на PHP настройката ограничава кои разширения на файлове PHP-FPM изпълнява като основен скрипт. По подразбиране са .php и .phar. Който ги ограничи до .php, предотвратява например качени файлове с изображения да се изпълняват като PHP, ако уеб сървърът е конфигуриран неправилно.

Опасна ли е статус страницата на PHP-FPM?

Тя издава подробности за работещите процеси и заявки. Ако е публично достъпна без защита, улеснява ориентирането на атакуващите. Според ръководството тя е активна само ако е зададен pm.status_path. Тогава уеб сървърът трябва да ограничи пътя до вътрешни адреси.

Източници

Незабавен контакт

Всеки час има значение. Пишете ни сега.

Опишете накратко системата, версията на PHP и какво сте забелязали. Ние се свързваме с Вас, уточняваме ситуацията и работим отдалечено, докато инцидентът бъде приключен и документиран.

Незабавна помощ