Накратко: open_basedir ограничава директориите, до които PHP има достъп. Сама по себе си това е само допълнителна бариера. Ефективна изолация за всеки уебсайт се получава едва от взаимодействието: отделен системен потребител, отделен PHP-FPM пул, отделна temp папка и отделни достъпи до базата данни. Тогава проникването в един уебсайт остава ограничено до него.
Защо изолацията след PHP2Shell решава какви са щетите
На много сървъри работят няколко уебсайта един до друг: фирменият сайт, магазин, стара кампанийна страница, а при агенциите често десетки клиентски проекта. Често те споделят един системен потребител и един PHP процес. Ако един от тях бъде компрометиран, всички останали са изложени.
PHP2Shell прави този риск осезаем. Уязвимостите CVE-2026-109618 и CVE-2026-109619 позволяват изпълнение на злонамерен код без вход в системата, независимо от CMS. Според медийни съобщения още на 17.10.2026 е имало първи опит за атака, а пачовете последваха на 21.10. Решението е актуализацията. Дали една атака в предходния период засяга един или десет уебсайта обаче решава изолацията.
Особено при втората уязвимост се добавя още една мисъл: според проекта PHP вътрешното състояние на една заявка може да остане в worker процеса и да бъде използвано от по-късна заявка в същия worker. Отделните пулове за всеки уебсайт гарантират, че уебсайтовете така или иначе не споделят worker процеси.
Какво постига open_basedir
С open_basedir определяте списък от директории. Файловите функции на PHP като fopen, include или file_get_contents тогава отказват достъп до всичко извън този списък. Внедрен скрипт така не може лесно да чете конфигурационните файлове на съседния уебсайт.
Границите са важни: проверката се извършва в рамките на PHP. Програми, стартирани извън PHP, не са обект на нея, а грешки в интерпретатора могат да я заобиколят. Затова open_basedir винаги принадлежи заедно със заключени системни функции, както е описано в наръчника Правилно използване на disable_functions, и преди всичко с разделяне на ниво операционна система.
Изолация за всеки уебсайт в четири слоя
Устойчивото разделяне се гради на няколко слоя. Всеки улавя това, което предходният не постига.
| Слой | Мярка | Ефект |
|---|---|---|
| Операционна система | отделен системен потребител за всеки уебсайт | Файловете на други уебсайтове не могат да се четат |
| PHP процеси | отделен PHP-FPM пул със собствен сокет | няма общ worker, собствени настройки |
| PHP конфигурация | open_basedir, отделна tmp и session папка |
допълнителна бариера, няма общи временни файлове |
| Данни | отделен потребител на базата данни с права само за собствената база | няма достъп до чужди данни на клиенти |
При висока нужда от защита, например при магазини с обработка на плащания или портали със здравни данни, се добавят контейнери или разделени сървъри.
Конфигуриране на open_basedir в PHP-FPM пула
Следният пример показва пул за уебсайт със собствен потребител seite1. Пътищата и номера на версията адаптирайте към Вашата система.
; /etc/php/8.3/fpm/pool.d/seite1.conf
[seite1]
user = seite1
group = seite1
listen = /run/php/seite1.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = ondemand
pm.max_children = 10
php_admin_value[open_basedir] = /var/www/seite1/:/var/www/seite1-tmp/
php_admin_value[upload_tmp_dir] = /var/www/seite1-tmp/
php_admin_value[sys_temp_dir] = /var/www/seite1-tmp/
php_admin_value[session.save_path] = /var/www/seite1-tmp/sessions
php_admin_value[error_log] = /var/log/php/seite1.error.log
php_admin_flag[session.upload_progress.enabled] = off
Последният ред веднага въвежда и преходната мярка на php.net за PHP2Shell. Тя действа само от пула, php.ini или конфигурацията на сървъра, не чрез ini_set() или .user.ini. Папките създавате с подходящи права:
sudo useradd --system --home /var/www/seite1 --shell /usr/sbin/nologin seite1
sudo mkdir -p /var/www/seite1-tmp/sessions
sudo chown -R seite1:seite1 /var/www/seite1-tmp
sudo chmod 700 /var/www/seite1-tmp
Как трябва да изглеждат правата в самата уеб директория, описва наръчникът Права за файлове на уеб сървъра.
Свързване на уеб сървъра и проверка на резултата
В Nginx всеки уебсайт сочи към собствения си сокет. Така никоя заявка не попада в пула на друг уебсайт.
server {
server_name seite1.example;
root /var/www/seite1/public;
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/seite1.sock;
}
}
Допълнителни указания за тази комбинация ще намерите на страницата Защита на Nginx с PHP-FPM. След рестарта проверете дали пуловете действително работят разделено:
sudo systemctl restart php8.3-fpm
# Всеки пул трябва да работи под собствения си потребител
ps -eo user,pid,cmd | grep "[p]hp-fpm: pool"
След това тествайте всички функции на уебсайта: качвания, обработка на изображения, кешове, планирани задачи. Съобщенията за грешки с указание open_basedir restriction в лога на грешките показват кой път още липсва. Добавяйте само пътища, които приложението действително изисква, и никога цялата файлова система.
Агенциите с много клиентски сайтове трябва да поддържат конфигурацията на пула като шаблон. Така всеки нов уебсайт получава разделянето автоматично, вместо да се налага по-късно да го добавяте. Основна информация за този случай има на страницата Партньор по сигурността за агенции.
Типични спънки при преминаването
Преминаването към разделени пулове е планируемо, но има няколко повтарящи се капана. Най-честият засяга споделените библиотеки: ако например фреймуърк или папка с шрифтове е извън директорията на уебсайта, този път трябва да се добави само за четене в open_basedir. По-добре е такива зависимости да се пренесат в самия проект.
Вторият капан са сесиите. Ако мястото за съхранение се смени, всички посетители веднъж се отписват, а текущите кошници се губят. Затова планирайте преминаването в спокоен времеви прозорец и го обявете вътрешно.
Трето, планираните задачи често се изпълняват през командния ред и така под друг потребител от уебсайта. Проверете cron задачите и опашките и ги пуснете под новия потребител на уебсайта, иначе се получават файлове с грешен собственик, които PHP по-късно не може да променя.
Накрая, всеки пул трябва да има собствени граници за процеси и памет. Уебсайт, който попада под натоварване или бива атакуван, така не може да повали и останалите.
Как конкретно помага PHP SOS?
- Установяваме кои уебсайтове днес споделят потребители, процеси и бази данни.
- Създаваме за всеки уебсайт отделни потребители, пулове, temp папки и достъпи до базата данни, без да променяме приложенията.
- Тестваме всеки уебсайт след преминаването и отстраняваме целенасочено липсващите пътища.
- Документираме разделянето като шаблон за бъдещи проекти.
Как това се вписва в цялостна концепция, описва услугата Заздравяване на сървъри за PHP уеб сървъри.
Често задавани въпроси
Достатъчно ли е open_basedir, за да се разделят уебсайтовете един от друг?
Не. open_basedir е допълнителна бариера в рамките на PHP, а не твърдо разделяне. Изолацията става надеждна едва с отделни системни потребители и пулове за всеки уебсайт, а при по-висока нужда от защита с контейнери или разделени сървъри.
Защо след задаването на open_basedir качванията вече не работят?
Обикновено в списъка липсва папката за временни файлове. Създайте за всеки уебсайт собствена tmp папка, впишете я в open_basedir и задайте upload_tmp_dir и sys_temp_dir на тази папка.
Може ли приложението само да отмени open_basedir?
Приложението може да ограничи настройката по време на изпълнение само допълнително, но не и да я облекчи. Все пак задайте open_basedir чрез php_admin_value в пула, за да е стойността еднозначно фиксирана.
Възможна ли е изолация и при споделен хостинг?
Това зависи от хостинг доставчика. Много оферти разделят клиентите чрез отделни потребители и PHP процеси. Попитайте как е реализирано разделянето, особено ако няколко Ваши уебсайта са в един пакет.