Aktualna sytuacja: PHP2Shell. Dwie krytyczne luki w PHP (CVSS 9,2) umożliwiają wykonanie złośliwego kodu bez logowania. Poprawki od 21.10.2026.Co należy teraz zrobić →

Jak PHP generuje stronę internetową: droga żądania

Co dzieje się między kliknięciem a gotową stroną: serwer WWW, SAPI, kompilator, OPcache i Zend VM w siedmiu krokach oraz dlaczego PHP2Shell uderza właśnie w ten przebieg.

Stan 4 min czytaniaWiedza o PHP

Krótko: Gdy przeglądarka żąda strony PHP, serwer WWW przyjmuje żądanie i przekazuje je przez interfejs (SAPI) do PHP. PHP tłumaczy skrypt na bajtkod, wykonuje go w Zend Engine i zwraca wynik, zwykle HTML, serwerowi WWW. Potem stan żądania jest sprzątany, aby następne zaczynało od czystego stanu.

Co się dzieje, gdy ktoś otwiera Państwa stronę?

Dla odwiedzającego to jedno kliknięcie. Na serwerze w ciągu milisekund przebiega wiele kroków. Kto zna ten przebieg, lepiej rozumie, dlaczego aktualizacje, restarty i konfiguracja są tak ważne i dlaczego luka w samym PHP waży więcej niż luka we wtyczce.

Podręcznik PHP wymienia trzy elementy potrzebne dla strony w PHP: interpreter PHP (jako CGI lub moduł serwera), serwer WWW i przeglądarkę. Interpreter to program, który czyta i wykonuje kod PHP. To, jak jest połączony z serwerem WWW, określa tryb pracy.

Jak działa PHP? Siedem kroków żądania

  1. Żądanie: Przeglądarka wysyła do serwera żądanie HTTP, na przykład GET /kontakt.php.
  2. Serwer WWW: Apache, Nginx lub LiteSpeed przyjmują żądanie. Pliki statyczne, takie jak obrazy, wydają samodzielnie. Dla plików .php wywołują PHP.
  3. Przekazanie przez SAPI: Interfejs serwera (SAPI) przekazuje do PHP dane żądania, takie jak nagłówki, parametry i dane formularzy. W PHP-FPM odbywa się to przez protokół FastCGI, w mod_php bezpośrednio w procesie Apache. Szczegóły na stronie SAPI wyjaśnione.
  4. Przygotowanie żądania: PHP zapisuje dane żądania w zmiennych takich jak $_GET, $_POST, $_COOKIE i $_FILES oraz rezerwuje pamięć dla żądania.
  5. Tłumaczenie: Skrypt jest rozbijany na elementy (tokeny), z nich powstaje abstrakcyjne drzewo składni (AST), a z niego opcody, rodzaj języka maszynowego dla PHP. Jeśli OPcache jest aktywny, ten krok jest pomijany, o ile skrypt leży już w pamięci podręcznej.
  6. Wykonanie: Maszyna wirtualna Zend Engine przetwarza opcody, odpytuje bazy danych, czyta pliki i tworzy wyjście.
  7. Odpowiedź i sprzątanie: Wyjście wraca przez SAPI do serwera WWW, a stamtąd do przeglądarki. Następnie PHP zwalnia pamięć żądania i resetuje stan.

AST istnieje od PHP 7. Według powiązanego RFC parser tworzył wcześniej opcody bezpośrednio podczas wczytywania; podział na trzy fazy ułatwił utrzymanie kompilatora.

Przykład: co skrypt widzi z żądania

Poniższy nieszkodliwy skrypt pokazuje, jakie informacje PHP otrzymuje z żądania i w jakim trybie pracy działa:

<?php
header('Content-Type: text/plain; charset=utf-8');

echo 'Betriebsart (SAPI): ' . PHP_SAPI . "\n";
echo 'PHP-Version: ' . PHP_VERSION . "\n";
echo 'Methode: ' . ($_SERVER['REQUEST_METHOD'] ?? '-') . "\n";
echo 'Speicher in dieser Anfrage: ' . memory_get_usage() . " Bytes\n";

Na serwerze z PHP-FPM PHP_SAPI zwraca wartość fpm-fcgi, w Apache z mod_php apache2handler. Takie pliki kontrolne proszę umieszczać w katalogu publicznym tylko na krótko i nigdy na stałe, ponieważ informacje o wersji pomagają także atakującym w orientacji.

Gdzie wchodzą pamięć podręczna bajtkodu i JIT

Tłumaczenie w kroku 5 kosztuje czas. OPcache przechowuje według podręcznika prekompilowany bajtkod we wspólnej pamięci i oszczędza PHP wczytywania oraz rozbijania skryptów przy każdym żądaniu. Od PHP 8.0 dodatkowo kompilator JIT może tworzyć z opcodów prawdziwy kod maszynowy. Według RFC dotyczącego JIT jest to niemal samodzielna część OPcache.

Faza Wynik Czy jest buforowana?
Analiza leksykalna strumień tokenów nie
Parsowanie abstrakcyjne drzewo składni (AST) nie
Kompilacja opcody (tablice op dla pliku i funkcji) tak, w OPcache
JIT (opcjonalnie) kod maszynowy tak, w pamięci OPcache
Wykonanie wyjście strony nie

Pamięć podręczna dotyczy tylko przetłumaczonego kodu. Dane pojedynczego żądania, na przykład wpisy w formularzu czy wartości sesji, nie są współdzielone przez OPcache.

Dlaczego PHP2Shell uderza właśnie w ten przebieg

Obie luki PHP2Shell nie dotyczą jednej aplikacji, lecz samego przebiegu. W przypadku CVE-2026-109618 stan braku pamięci (out of memory) może przerwać PHP, gdy dane żądania są dopiero częściowo przygotowane, czyli w kroku 4. Przy późniejszym sprzątaniu nieprawidłowe dane mogą zostać potraktowane jako prawidłowe.

W przypadku CVE-2026-109619 wewnętrzny stan żądania może pozostać po zwolnieniu pamięci. Późniejsze żądanie w tym samym workerze może go użyć, zanim zostanie zresetowany. Dotyczy to kroku 7, czyli sprzątania. Tło wyjaśniamy na stronie CVE-2026-109619 oraz w artykule o cyklu życia żądania.

Wynika z tego: środki ochrony w kodzie aplikacji, na przykład wtyczki bezpieczeństwa, działają dopiero w kroku 6. W mod_php według zespołu PHP pokazano nawet exploit, zanim w ogóle zacznie działać kod aplikacji. Skuteczna jest tylko aktualizacja PHP do 8.5.12, 8.4.27, 8.3.36 lub 8.2.35 i restart wszystkich procesów PHP, ponieważ długo żyjące workery w przeciwnym razie nadal wykonują stary kod.

Jak konkretnie pomaga PHP SOS?

  • Uwidocznienie przebiegu: Ustalamy, jaki tryb pracy, jaka konfiguracja i jaka pamięć podręczna są faktycznie aktywne na Państwa serwerze.
  • Prawidłowa aktualizacja: Instalujemy aktualizację PHP i na podstawie czasów startu sprawdzamy, że nie działa już żaden stary proces.
  • Zabezpieczenie warstw: W ramach utwardzania serwera ograniczamy rozmiary żądań, pamięć i uprawnienia tam, gdzie działają: przed kodem aplikacji.
  • Sprawdzenie śladów: Na serwerach dostępnych bez zabezpieczeń szukamy oznak włamania.

Częste pytania

Czy kod PHP jest tłumaczony od nowa przy każdym wywołaniu?

Bez pamięci podręcznej tak: PHP rozbija skrypt, buduje drzewo składni i tworzy z niego opcody. Przy aktywnym OPcache opcody leżą we wspólnej pamięci i są używane ponownie, dopóki plik się nie zmieni.

Co pozostaje w pamięci po żądaniu?

Co do zasady stan żądania jest na końcu sprzątany, aby następne żądanie zaczynało od czystego stanu. Długo żyją tylko takie rzeczy jak OPcache czy trwałe połączenia. Właśnie to sprzątanie dotyczy CVE-2026-109619.

Dlaczego po aktualizacji trzeba zrestartować PHP?

W PHP-FPM i mod_php procesy działają nieprzerwanie i mają załadowany stary kod programu. Nowe pliki na dysku niczego tu nie zmieniają. Dopiero restart ładuje poprawiony kod.

Czy serwer WWW bez PHP jest bezpieczniejszy?

Ma mniejszą powierzchnię ataku, ponieważ żadna logika programu nie reaguje na żądania. Dla czysto statycznych treści to realna opcja. Dla sklepów, formularzy i logowania potrzebny jest jednak język po stronie serwera, a wtedy liczy się jego utrzymanie.

Źródła

Kontakt natychmiast

Liczy się każda godzina. Proszę napisać do nas teraz.

Proszę krótko opisać system, wersję PHP i obserwacje. Skontaktujemy się z Państwem, ustalimy sytuację i będziemy pracować zdalnie, aż incydent zostanie zamknięty i udokumentowany.

Natychmiastowa pomoc