# open_basedir i izolacja każdej strony

> Jak ustawić open_basedir i czysto rozdzielić strony: osobny użytkownik, osobna pula PHP-FPM, osobne foldery tymczasowe. Z przykładem konfiguracji Nginx.

Źródło: https://phpsos.de/pl/ratgeber/open-basedir/  
Stan: 25.10.2026  
Dostawca: PHP SOS, Pomoc awaryjna PHP i bezpieczeństwo serwerów. Natychmiastowa pomoc przez WhatsApp: https://wa.me/491736494914?text=Dzie%C5%84%20dobry%2C%20PHP%20SOS%2C%20potrzebujemy%20pomocy%20z%20naszym%20serwerem%20PHP.%20Firma%3A%20%E2%80%A6%20Strona%20internetowa%3A%20%E2%80%A6

**Krótko:** `open_basedir` ogranicza katalogi, do których PHP ma dostęp. Samo w sobie jest to tylko dodatkowa bariera. Skuteczna izolacja każdej strony powstaje dopiero we współdziałaniu: osobny użytkownik systemowy, osobna pula PHP-FPM, osobny folder tymczasowy i osobne dostępy do bazy danych. Wtedy włamanie na jedną stronę pozostaje ograniczone do tej strony.

## Dlaczego izolacja po PHP2Shell decyduje o rozmiarze szkody

Na wielu serwerach obok siebie działa kilka stron: strona firmowa, sklep, stara strona kampanii, a w agencjach często dziesiątki projektów klientów. Często dzielą one jednego użytkownika systemowego i jeden proces PHP. Jeśli jedna z nich zostanie skompromitowana, wszystkie pozostałe są odsłonięte.

PHP2Shell czyni to ryzyko namacalnym. Luki CVE-2026-109618 i CVE-2026-109619 umożliwiają wykonanie złośliwego kodu bez logowania, niezależnie od CMS. Według doniesień medialnych pierwsza próba ataku miała miejsce już 17.10.2026, a poprawki pojawiły się 21.10. Rozwiązaniem jest aktualizacja. To, czy atak w okresie wcześniejszym dotknie jedną stronę czy dziesięć, rozstrzyga jednak izolacja.

Zwłaszcza przy drugiej luce dochodzi kolejna myśl: według projektu PHP wewnętrzny stan żądania może pozostać w procesie roboczym i zostać wykorzystany przez późniejsze żądanie w tym samym procesie. Oddzielne pule dla każdej strony sprawiają, że strony i tak nie dzielą procesów roboczych.

## Co daje open_basedir

Za pomocą `open_basedir` ustalają Państwo listę katalogów. Funkcje plikowe PHP, takie jak `fopen`, `include` lub `file_get_contents`, odmawiają wtedy dostępu do wszystkiego poza tą listą. Wprowadzony skrypt nie może więc bez trudu czytać plików konfiguracyjnych sąsiedniej strony.

Granice są ważne: kontrola odbywa się wewnątrz PHP. Programy uruchamiane poza PHP jej nie podlegają, a błędy w interpreterze mogą ją obejść. Dlatego `open_basedir` zawsze powinno iść w parze z zablokowanymi funkcjami systemowymi, jak opisuje poradnik [Jak prawidłowo stosować disable_functions](https://phpsos.de/pl/ratgeber/disable-functions/), a przede wszystkim z rozdzieleniem na poziomie systemu operacyjnego.

## Izolacja każdej strony w czterech warstwach

Wytrzymałe rozdzielenie opiera się na kilku warstwach. Każda przechwytuje to, czego nie robi poprzednia.

| Warstwa | Środek | Efekt |
|---|---|---|
| System operacyjny | osobny użytkownik systemowy dla każdej strony | pliki innych stron nie są odczytywalne |
| Procesy PHP | osobna pula PHP-FPM z własnym gniazdem | brak wspólnego procesu roboczego, własne ustawienia |
| Konfiguracja PHP | `open_basedir`, własny folder tmp i sesji | dodatkowa bariera, brak wspólnych plików tymczasowych |
| Dane | osobny użytkownik bazy danych z uprawnieniami tylko do własnej bazy | brak dostępu do cudzych danych klientów |

Przy wysokich potrzebach ochrony, na przykład w sklepach z obsługą płatności lub portalach z danymi zdrowotnymi, dochodzą kontenery lub osobne serwery.

## Konfiguracja open_basedir w puli PHP-FPM

Poniższy przykład pokazuje pulę dla strony z własnym użytkownikiem `seite1`. Ścieżki i numer wersji proszę dostosować do swojego systemu.

```ini
; /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
```

Ostatni wiersz od razu ustawia środek przejściowy PHP2Shell z php.net. Działa on tylko z puli, php.ini lub konfiguracji serwera, a nie przez `ini_set()` ani `.user.ini`. Foldery proszę utworzyć z odpowiednimi uprawnieniami:

```bash
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
```

Jak powinny wyglądać uprawnienia w samym katalogu WWW, opisuje poradnik [Uprawnienia do plików na serwerze WWW](https://phpsos.de/pl/ratgeber/dateirechte-webserver/).

## Podłączenie serwera WWW i sprawdzenie wyniku

W Nginx każda strona wskazuje na swoje własne gniazdo. Dzięki temu żadne żądanie nie trafia do puli innej strony.

```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;
    }
}
```

Dalsze wskazówki dotyczące tego połączenia znajdą Państwo na stronie [Zabezpieczanie Nginx z PHP-FPM](https://phpsos.de/pl/server/nginx-php-fpm/). Po restarcie sprawdzają Państwo, czy pule rzeczywiście działają oddzielnie:

```bash
sudo systemctl restart php8.3-fpm
# Każda pula powinna działać pod własnym użytkownikiem
ps -eo user,pid,cmd | grep "[p]hp-fpm: pool"
```

Następnie proszę przetestować wszystkie funkcje strony: uploady, przetwarzanie obrazów, pamięci podręczne, zaplanowane zadania. Komunikaty o błędach z wzmianką o `open_basedir restriction` w logu błędów pokazują, której ścieżki jeszcze brakuje. Proszę dodawać tylko ścieżki, których aplikacja naprawdę potrzebuje, i nigdy całego systemu plików.

> **Wskazówka:**
> Agencje z wieloma stronami klientów powinny utrzymywać konfigurację puli jako szablon. Dzięki temu każda nowa strona automatycznie otrzymuje rozdzielenie zamiast konieczności dozbrajania go później. Tło dla tego przypadku znajdą Państwo na stronie [Partner bezpieczeństwa dla agencji](https://phpsos.de/pl/branchen/agenturen-white-label/).

## Typowe pułapki przy przejściu

Przejście na oddzielne pule jest planowalne, ale ma kilka powtarzających się pułapek. Najczęstsza dotyczy współdzielonych bibliotek: jeśli na przykład framework lub folder z czcionkami leży poza katalogiem strony, ścieżkę tę trzeba dodać do `open_basedir` z dostępem do odczytu. Lepiej przenieść takie zależności do samego projektu.

Drugą pułapką są sesje. Jeśli zmienia się miejsce zapisu, wszyscy odwiedzający są raz wylogowani, a trwające koszyki przepadają. Przejście proszę więc zaplanować w spokojnym oknie czasowym i zapowiedzieć je wewnętrznie.

Po trzecie, zaplanowane zadania często działają przez wiersz poleceń, a tym samym pod innym użytkownikiem niż strona. Proszę sprawdzić zadania cron i kolejki i uruchamiać je pod nowym użytkownikiem strony, w przeciwnym razie powstaną pliki z niewłaściwym właścicielem, których PHP później nie będzie mógł zmieniać.

Wreszcie każda pula powinna mieć własne limity procesów i pamięci. Strona, która znajdzie się pod obciążeniem lub zostanie zaatakowana, nie może wtedy rzucić na kolana pozostałych.

## Jak konkretnie pomaga PHP SOS?

- Ustalamy, które strony dzielą dziś użytkowników, procesy i bazy danych.
- Zakładamy dla każdej strony własnych użytkowników, pule, foldery tymczasowe i dostępy do bazy danych, bez zmiany aplikacji.
- Testujemy każdą stronę po przejściu i celowo usuwamy brakujące ścieżki.
- Dokumentujemy rozdzielenie jako szablon dla przyszłych projektów.

Jak to wpisuje się w całościową koncepcję, opisuje usługa [Utwardzanie serwera dla serwerów WWW z PHP](https://phpsos.de/pl/leistungen/server-haertung/).


## Częste pytania

**Czy open_basedir wystarczy, by rozdzielić strony?**  
Nie. open_basedir to dodatkowa bariera wewnątrz PHP, a nie twarde rozdzielenie. Izolacja staje się niezawodna dopiero dzięki osobnym użytkownikom systemowym i pulom dla każdej strony, a przy wyższych potrzebach ochrony dzięki kontenerom lub osobnym serwerom.

**Dlaczego po ustawieniu open_basedir uploady przestały działać?**  
Najczęściej na liście brakuje folderu plików tymczasowych. Proszę utworzyć dla każdej strony własny folder tmp, wpisać go do open_basedir i ustawić upload_tmp_dir oraz sys_temp_dir na ten folder.

**Czy aplikacja może sama zniesić open_basedir?**  
Aplikacja może w czasie działania ustawienie tylko dalej ograniczyć, a nie złagodzić. Mimo to proszę ustawić open_basedir przez php_admin_value w puli, aby wartość była jednoznacznie ustalona.

**Czy izolacja jest możliwa także na shared hostingu?**  
To zależy od dostawcy hostingu. Wiele ofert rozdziela klientów przez osobnych użytkowników i procesy PHP. Proszę zapytać, jak rozdzielenie jest zrealizowane, zwłaszcza jeśli kilka Państwa stron znajduje się w jednym pakiecie.

## Źródła

- [php.net: komunikaty o bezpieczeństwie](https://www.php.net/)
- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/)
- [BSI IT-Grundschutz](https://www.bsi.bund.de/DE/Themen/Unternehmen-und-Organisationen/Standards-und-Zertifizierung/IT-Grundschutz/it-grundschutz_node.html)
