Krótko: Administratorom bez zaplecza programistycznego wystarczy pięć podstaw, aby bezpiecznie prowadzić PHP: PHP składa się z kilku programów (wiersz poleceń, PHP-FPM, moduł Apache), każdy z własną wersją; ustawienia działają w warstwach od php.ini po aplikację; PHP-FPM rozdziela żądania na workery w pulach; aktualizacja działa dopiero po restarcie wszystkich procesów; a logi są najważniejszą wskazówką, gdy coś jest nie tak. Kto zna te punkty, może szybko i w sposób możliwy do udowodnienia zamykać luki takie jak PHP2Shell.
Z czego składa się PHP na serwerze
PHP nie jest pojedynczym programem. Na typowym serwerze Linux występuje kilka wariantów, z których każdy jest podłączony przez interfejs serwera (SAPI):
| Wariant | Typowa nazwa | Do czego |
|---|---|---|
| Wiersz poleceń (CLI) | php, php8.3 |
zadania cron, Composer, skrypty konserwacyjne |
| PHP-FPM | php-fpm, php-fpm8.3 |
żądania webowe za Nginx lub Apache |
| Moduł Apache | mod_php, libphp |
żądania webowe bezpośrednio w procesie Apache |
| CGI | php-cgi |
starsze układy |
Każdy wariant może mieć inną wersję i inne php.ini. Na wielu serwerach równolegle działa ponadto kilka wersji PHP, na przykład 8.2 i 8.4. Przy aktualizacji każdą trzeba rozpatrzyć osobno. Jak działają interfejsy, wyjaśnia artykuł PHP-FPM wyjaśniony.
Który wariant faktycznie obsługuje Państwa strony, ustalają Państwo na podstawie działających procesów i konfiguracji serwera WWW:
ps -eo pid,user,lstart,cmd | grep -E "php|httpd|apache2" | grep -v grep
apachectl -M 2>/dev/null | grep -i php # czy Apache ładuje moduł PHP?
ls /run/php/ 2>/dev/null # gniazda FPM, często osobne dla wersji i puli
Kolumna z czasem startu jest później ważna przy restarcie: wszystkie procesy PHP muszą zostać uruchomione po momencie aktualizacji. Jeśli procesy działają pod różnymi użytkownikami, wskazuje to na oddzielne pule, co jest dobre. Jeśli w Apache pojawia się moduł PHP, mimo że wszystkie strony mają działać przez FPM, jest to wskazówka na pozostałość z przeszłości, którą należy usunąć. Dla paneli hostingowych, takich jak Plesk czy cPanel, obowiązuje ta sama zasada, z tą różnicą, że panel pokazuje wersje i handlery dla każdej strony; rozstrzygające pozostaje jednak to, co faktycznie działa jako proces.
Najważniejsze polecenia dla administratorów
php -v # wersja wiersza poleceń
php --ini # załadowane php.ini i dodatkowo czytane katalogi
php --ini=diff # od PHP 8.5: odstępstwa od wartości domyślnych
php -m # wkompilowane i załadowane moduły
php --ri session # ustawienia rozszerzenia
php -l datei.php # sprawdzenie składni bez wykonania
php-fpm8.3 -v # wersja binarki FPM (nazwa zależy od dystrybucji)
php-fpm8.3 -t # test konfiguracji FPM bez restartu
systemctl status php8.3-fpm
Dwie uwagi z podręcznika: php -l znajduje błędy składni, ale nie błędy, które pojawiają się dopiero przy wykonaniu. Poza tym php -i wywołuje phpinfo(); jego wynik nie należy do publicznych plików w katalogu webowym.
Jak działają ustawienia PHP
Ustawienie można zadać w kilku miejscach. Kto gdzie co może zmieniać, reguluje tryb zmiany każdej dyrektywy:
- php.ini i conf.d: konfiguracja podstawowa dla wariantu, czytana przy starcie.
- Pula FPM:
php_valueiphp_admin_valuedla każdej puli. Wartości ustawionych przezphp_admin_valueaplikacja według podręcznika nie może nadpisać za pomocąini_set(). - Poziom katalogu:
.user.iniprzy FPM lub.htaccessprzy mod_php, tylko dla dyrektyw w trybieINI_PERDIRlubINI_ALL. - Aplikacja:
ini_set()w czasie działania, tylko dla dyrektyw w trybieINI_ALL.
Przykład: memory_limit ma tryb INI_ALL, może więc być zmieniony przez aplikację. post_max_size ma INI_PERDIR i nie da się go zmienić przez ini_set(). Dlatego php.net wymaga w środkach przejściowych PHP2Shell, aby ustawiać wartości tak, by aplikacje nie mogły ich nadpisać. Szczegóły o poziomach wyjaśnia artykuł php.ini wyjaśnione.
Pule PHP-FPM w skrócie
Pula to grupa workerów z własnym użytkownikiem, własnym gniazdem i własnymi ustawieniami. Najważniejsze dyrektywy według podręcznika:
[shop]
user = shop
group = shop
listen = /run/php/shop.sock
pm = dynamic ; static, dynamic lub ondemand
pm.max_children = 20 ; co najwyżej 20 jednoczesnych żądań
pm.max_requests = 500 ; odnawiać workera po 500 żądaniach
request_slowlog_timeout = 5s
slowlog = /var/log/php-fpm/shop-slow.log
php_admin_value[error_log] = /var/log/php-fpm/shop-error.log
php_admin_flag[log_errors] = on
Osobna pula dla każdej strony z własnym użytkownikiem rozdziela strony od siebie. security.limit_extensions jest domyślnie ustawione na .php .phar i zapobiega wykonywaniu przez FPM plików z innymi rozszerzeniami niż PHP. clear_env jest domyślnie włączone i trzyma zmienne środowiskowe z dala od workera.
Logi: gdzie administratorzy zaglądają
PHP zapisuje błędy w miejscu wskazanym przez error_log, PHP-FPM dodatkowo w swoim własnym logu, a przy wolnych żądaniach w slowlogu z backtrace. Do tego dochodzą logi dostępu i błędów serwera WWW. Proszę dopilnować, aby display_errors było w produkcji wyłączone, a log_errors włączone: błędy należą do logu, nie na stronę internetową. Logi powinny ponadto być rotowane i przechowywane przez określony czas, aby w razie potrzeby jeszcze istniały. Po PHP2Shell prasa branżowa zaleca przechowywanie logów serwera od 20.10.2026. Silnym sygnałem ostrzegawczym jest proces PHP-FPM lub serwera WWW, który uruchamia powłokę; jak to rozpoznać, opisuje artykuł Sygnał ostrzegawczy: serwer WWW uruchamia powłokę.
Lista kontrolna dla administratorów po PHP2Shell
- Wypisać wszystkie warianty i wersje PHP na serwerze, także nieużywane.
- Sprawdzić stan pakietu; przy backportach dystrybucji przeszukać changelog pod kątem CVE-2026-109618 i CVE-2026-109619.
- Zaktualizować do 8.5.12, 8.4.27, 8.3.36 lub 8.2.35 albo do potwierdzonego backportu.
- Zrestartować PHP-FPM, Apache i LiteSpeed oraz skontrolować czasy startu procesów.
- Kontrola krzyżowa za pomocą
php -r 'var_dump(ini_get("memory_hard_limit_percent"));';bool(false)oznacza według podręcznika wersję dotkniętą. - Zabezpieczyć logi i sprawdzić je pod kątem nieprawidłowości.
Jak wiarygodnie udowodnić wersję i stan poprawek, opisuje artykuł Prawidłowe sprawdzanie wersji PHP i stanu poprawek.
Jak konkretnie pomaga PHP SOS?
W ramach umowy serwisowej bezpieczeństwa przejmujemy podstawową opiekę nad PHP razem z Państwa zespołem:
- Inwentarz: wszystkie warianty PHP, wersje, pule i miejsca konfiguracji na każdym serwerze.
- Konfiguracja: wartości istotne dla bezpieczeństwa ustawione przez
php_admin_value, pule oddzielone dla każdej strony. - Aktualizacje: instalacja, restart, kontrola i dokumentacja przy każdym wydaniu bezpieczeństwa.
- Przekazywanie wiedzy: Wyjaśniamy Państwa administratorom, co zmieniliśmy i dlaczego.
Częste pytania
Dlaczego php -v pokazuje inną wersję niż strona internetowa?
Wiersz poleceń, PHP-FPM i moduł Apache to osobne programy z własną wersją i własnym php.ini. php -v pokazuje tylko wiersz poleceń. Dla strony liczy się wersja binarki, która faktycznie obsługuje żądania.
Które php.ini obowiązuje na moim serwerze?
Dla wiersza poleceń pokazuje to php --ini. Dla PHP-FPM zwykle istnieje własne php.ini i dodatkowe pliki pul. Od PHP 8.5 php --ini=diff pokazuje, które wartości odbiegają od domyślnych.
Jaka jest różnica między php_value a php_admin_value?
Oba ustawiają opcje w puli FPM. Wartości ustawionych przez php_admin_value aplikacja według podręcznika nie może nadpisać za pomocą ini_set(). Dla ustawień istotnych dla bezpieczeństwa właściwym wyborem jest więc php_admin_value.
Czy aktualizacja bez restartu wystarcza?
Nie. Działające procesy PHP zachowują stary kod w pamięci. Po aktualizacji trzeba zrestartować PHP-FPM, Apache z mod_php lub LiteSpeed, w przeciwnym razie nadal działa podatna wersja.