Krótko: CGI (Common Gateway Interface) to stary interfejs, w którym serwer WWW dla każdego żądania uruchamia nowy program, w przypadku PHP program php-cgi. FastCGI jest jego rozwinięciem: procesy PHP działają nieprzerwanie i przyjmują wiele żądań przez gniazdo. PHP-FPM to najważniejsza implementacja FastCGI dla PHP. Dla bezpieczeństwa istotne są przede wszystkim ustawienia cgi.* oraz zasada, że dostęp FastCGI nigdy nie może być publicznie osiągalny.
Czym jest CGI?
CGI to jedna z najstarszych metod, za pomocą których serwery WWW tworzą treści dynamiczne. Podręcznik PHP odsyła przy ustawieniu cgi.rfc2616_headers do RFC 3875, specyfikacji Common Gateway Interface. Także początki PHP to programy CGI: Rasmus Lerdorf napisał w 1994 roku pierwsze „Personal Home Page Tools” jako binarne pliki CGI w C.
Zasada: dla każdego żądania serwer WWW uruchamia nowy proces, przekazuje dane żądania przez zmienne środowiskowe i standardowe wejście, a odpowiedź odczytuje ze standardowego wyjścia. Potem proces się kończy. Według podręcznika PHP w CGI i CLI czyta swój php.ini od nowa przy każdym wywołaniu, w modułach serwera tylko przy starcie.
To czyni CGI odpornym, bo każde żądanie zaczyna się od świeżego procesu. Czyni je jednak także wolnym: uruchomienie procesu, wczytanie konfiguracji i inicjalizacja rozszerzeń kosztują czas przy każdym żądaniu.
Czym jest FastCGI?
FastCGI rozwiązuje problem wydajności, utrzymując procesy przy życiu. Serwer WWW łączy się przez gniazdo Unix lub port TCP z działającym procesem i wysyła mu żądanie w protokole FastCGI. Proces je obsługuje i czeka na następne.
| Cecha | CGI | FastCGI z php-cgi | FastCGI z PHP-FPM |
|---|---|---|---|
| Proces na żądanie | tak | nie | nie |
| Nazwa SAPI | cgi-fcgi |
cgi-fcgi |
fpm-fcgi |
| Pule z własnym użytkownikiem | nie | nie | tak |
| Sterowanie procesami | serwer WWW | moduł serwera WWW, np. mod_fcgid | własny proces master |
.user.ini jest czytany |
tak | tak | tak |
Według podręcznika PHP-FPM jest podstawową implementacją FastCGI w PHP. Uzupełnia protokół o zarządzanie procesami, pule, strony statusu i slowlog. Szczegóły podajemy na stronie PHP-FPM wyjaśniony.
Ustawienia cgi w php.ini
Dla pracy w trybie CGI PHP zna własne ustawienia. Poniższe wartości i opisy pochodzą z podręcznika PHP:
cgi.force_redirect(domyślnie 1,INI_SYSTEM): według podręcznika konieczne, aby bezpiecznie prowadzić PHP jako CGI pod większością serwerów WWW. Wyłączać tylko „na własne ryzyko”; pod IIS musi być wyłączone.cgi.fix_pathinfo(domyślnie 1,INI_SYSTEM): zapewnia prawidłowe wartościPATH_INFOiPATH_TRANSLATED. Skrypty powinny używaćSCRIPT_FILENAMEzamiastPATH_TRANSLATED.cgi.discard_path(domyślnie 0,INI_SYSTEM): pozwala bezpiecznie umieścić plik binarny CGI poza katalogiem WWW, bez możliwości obejścia ochrony.htaccess.fastcgi.impersonate(domyślnie 0,INI_SYSTEM): istotne tylko dla IIS w systemie Windows.user_ini.filenameiuser_ini.cache_ttl(domyślnie.user.inii 300 sekund): sterują tym, czy i jak często PHP czyta pliki.user.ini.
W Nginx do tego należy prawidłowe przekazanie ścieżki skryptu. Czytelny wzorzec podstawowy, bez gwarancji dla każdego środowiska:
location ~ \.php$ {
try_files $uri =404; # przekazywać do PHP tylko istniejące pliki
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
Wiersz try_files $uri =404; zapobiega przekazywaniu do PHP żądań o nieistniejące ścieżki .php.
Dlaczego otwarty dostęp FastCGI jest niebezpieczny
Podręcznik PHP wyraźnie ostrzega: kto może otworzyć połączenie FastCGI z PHP, kontroluje konfigurację żądania, na przykład auto_prepend_file, i może przez to wykonać dowolny kod. Powód jest taki, że serwery WWW mogą przesyłać ustawienia PHP przez parametry FastCGI, takie jak PHP_VALUE i PHP_ADMIN_VALUE.
Wynikają z tego jasne zasady:
- PHP-FPM lub php-cgi w trybie FastCGI podłączać tylko przez gniazdo Unix, jeśli serwer WWW działa na tym samym hoście.
- Przy TCP ustawić
listen.allowed_clientsi zablokować port w zaporze; wskazówki w artykule Zapora dla serwera WWW. - Uprawnienia gniazda utrzymywać wąskie przez
listen.owner,listen.groupilisten.mode.
Proszę sprawdzić poleceniem ss -lntp | grep -i php, czy jakiś proces PHP nasłuchuje na adresie TCP. Powiązanie z 0.0.0.0 lub z adresem publicznym wymaga pilnego działania.
CGI, FastCGI i PHP2Shell
PHP2Shell dotyczy zarówno php-cgi, jak i PHP-FPM. Dla obu obowiązuje: aktualizacja do 8.5.12, 8.4.27, 8.3.36 lub 8.2.35 albo do potwierdzonego backportu, a następnie zakończenie i ponowne uruchomienie wszystkich działających procesów PHP. W konfiguracjach FastCGI z php-cgi procesy często działają dalej niezauważone, ponieważ żadna osobna usługa ich nie zarządza. Jak znaleźć i wycofać ten stary balast, opisujemy na stronie php-cgi: stary balast z ryzykiem. W Plesk warianty nazywają się inaczej; pomoc daje artykuł Plesk: zrozumieć programy obsługi PHP.
Jak konkretnie pomaga PHP SOS?
- Inwentaryzacja programów obsługi: Ustalamy, czy Państwa strony działają przez CGI, FastCGI z php-cgi czy PHP-FPM.
- Zamykanie dostępów: Sprawdzamy gniazda, porty i reguły zapory, aby żaden dostęp FastCGI nie był osiągalny z zewnątrz.
- Aktualizacja i porządkowanie: Aktualizujemy PHP i kończymy wszystkie stare procesy, także osierocone instancje php-cgi.
- Wycofanie: W ramach utwardzania serwera zastępujemy stare rozwiązania CGI przez PHP-FPM z własnymi pulami.
Częste pytania
Czy FastCGI to to samo co PHP-FPM?
Nie. FastCGI to protokół, którym serwer WWW rozmawia z procesem aplikacji. PHP-FPM to program, który realizuje ten protokół dla PHP i zarządza procesami. Także php-cgi potrafi mówić po FastCGI, ale nie oferuje pul.
Dlaczego zwykłe CGI uchodzi za przestarzałe?
W CGI serwer WWW uruchamia dla każdego żądania nowy proces, a PHP za każdym razem czyta swoją konfigurację. Kosztuje to czas i zasoby. FastCGI i PHP-FPM utrzymują procesy w gotowości, więc są wyraźnie wydajniejsze.
Czym jest .user.ini?
Plik .user.ini to mały plik konfiguracyjny w katalogu strony. Według podręcznika PHP czytają go tylko SAPI CGI i FastCGI, a więc także PHP-FPM. Może zawierać tylko ustawienia w trybach INI_PERDIR, INI_USER lub INI_ALL.
Jak rozpoznać, że na moim serwerze działa php-cgi?
Poleceniami tylko odczytowymi, takimi jak ps czy pgrep, szukać procesów o nazwie php-cgi, a w konfiguracji serwera WWW sprawdzić wpisy takie jak mod_fcgid, Action lub ScriptAlias z php-cgi. W panelach hostingowych tryb pracy często nazywa się CGI lub aplikacja FastCGI.