Stručně: CGI (Common Gateway Interface) je staré rozhraní, při kterém webový server pro každý požadavek spouští nový program, u PHP program php-cgi. FastCGI je jeho vývoj: procesy PHP běží trvale a přijímají mnoho požadavků přes socket. PHP-FPM je nejdůležitější implementace FastCGI pro PHP. Z hlediska bezpečnosti jsou důležitá především nastavení cgi.* a pravidlo, že přístup k FastCGI nesmí být nikdy veřejně dostupný.
Co je CGI?
CGI je jednou z nejstarších metod, jak webové servery vytvářejí dynamický obsah. Příručka PHP odkazuje u nastavení cgi.rfc2616_headers na RFC 3875, specifikaci Common Gateway Interface. I začátky PHP byly programy CGI: Rasmus Lerdorf napsal v roce 1994 první „Personal Home Page Tools“ jako binární soubory CGI v jazyce C.
Princip: Pro každý požadavek spustí webový server nový proces, předá data požadavku přes proměnné prostředí a standardní vstup a odpověď přečte ze standardního výstupu. Poté proces skončí. Podle příručky PHP čte PHP u CGI a CLI svůj php.ini při každém volání znovu, u serverových modulů jen při spuštění.
Díky tomu je CGI robustní, protože každý požadavek začíná s novým procesem. Je ale také pomalé: spuštění procesu, načtení konfigurace a inicializace rozšíření stojí při každém požadavku čas.
Co je FastCGI?
FastCGI řeší problém výkonu tím, že procesy zůstávají naživu. Webový server se připojí přes socket Unix nebo port TCP k běžícímu procesu a pošle mu požadavek v protokolu FastCGI. Proces jej zpracuje a čeká na další.
| Vlastnost | CGI | FastCGI s php-cgi | FastCGI s PHP-FPM |
|---|---|---|---|
| Proces pro každý požadavek | ano | ne | ne |
| Název SAPI | cgi-fcgi |
cgi-fcgi |
fpm-fcgi |
| Pooly s vlastním uživatelem | ne | ne | ano |
| Řízení procesů | webový server | modul webového serveru, např. mod_fcgid | vlastní hlavní proces |
.user.ini se čte |
ano | ano | ano |
PHP-FPM je podle příručky primární implementace FastCGI v PHP. Protokol doplňuje o správu procesů, pooly, stavové stránky a slowlog. Podrobnosti najdete v článku PHP-FPM vysvětleno.
Nastavení cgi v php.ini
Pro provoz CGI zná PHP vlastní nastavení. Následující hodnoty a popisy pocházejí z příručky PHP:
cgi.force_redirect(výchozí 1,INI_SYSTEM): podle příručky nutné pro bezpečný provoz PHP jako CGI pod většinou webových serverů. Vypnout jen „na vlastní riziko“; pod IIS musí být vypnuto.cgi.fix_pathinfo(výchozí 1,INI_SYSTEM): zajišťuje správné hodnotyPATH_INFOaPATH_TRANSLATED. Skripty mají používatSCRIPT_FILENAMEmístoPATH_TRANSLATED.cgi.discard_path(výchozí 0,INI_SYSTEM): umožňuje bezpečně uložit binární soubor CGI mimo webový adresář, aniž by šlo obejít ochranu.htaccess.fastcgi.impersonate(výchozí 0,INI_SYSTEM): relevantní jen pro IIS ve Windows.user_ini.filenameauser_ini.cache_ttl(výchozí.user.inia 300 sekund): řídí, zda a jak často PHP čte soubory.user.ini.
U Nginx k tomu patří čisté předání cesty ke skriptu. Čitelný základní vzor, bez záruky pro každé prostředí:
location ~ \.php$ {
try_files $uri =404; # předat PHP jen existující soubory
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
Řádek try_files $uri =404; zabraňuje tomu, aby se požadavky na neexistující cesty .php předávaly PHP.
Proč je otevřený přístup k FastCGI nebezpečný
Příručka PHP výslovně varuje: Kdo může otevřít spojení FastCGI k PHP, ovládá konfiguraci požadavku, například auto_prepend_file, a může tak provést libovolný kód. Důvodem je, že webové servery smějí posílat nastavení PHP s sebou přes parametry FastCGI jako PHP_VALUE a PHP_ADMIN_VALUE.
Z toho plynou jasná pravidla:
- PHP-FPM nebo php-cgi v režimu FastCGI napojovat jen přes socket Unix, pokud webový server běží na stejném hostiteli.
- U TCP nastavit
listen.allowed_clientsa port zablokovat ve firewallu; pokyny najdete v článku Firewall pro webové servery. - Oprávnění socketu držet úzká pomocí
listen.owner,listen.groupalisten.mode.
Pomocí ss -lntp | grep -i php ověřte, zda nějaký proces PHP naslouchá na adrese TCP. Vazba na 0.0.0.0 nebo na veřejnou adresu je naléhavý případ k řešení.
CGI, FastCGI a PHP2Shell
PHP2Shell postihuje jak php-cgi, tak PHP-FPM. Pro obojí platí: aktualizace na 8.5.12, 8.4.27, 8.3.36 nebo 8.2.35, případně na potvrzený backport, poté ukončit a znovu spustit všechny běžící procesy PHP. U nastavení FastCGI s php-cgi procesy často běží nepozorovaně dál, protože je nespravuje žádná samostatná služba. Jak tuto zděděnou zátěž najít a nahradit, popisuje článek php-cgi: zděděná zátěž s rizikem. V Plesku se varianty jmenují jinak; pomůže Plesk: pochopit handlery PHP.
Jak konkrétně pomáhá PHP SOS?
- Zmapovat handlery: Zjistíme, zda vaše weby běží přes CGI, FastCGI s php-cgi, nebo PHP-FPM.
- Uzavřít přístupy: Zkontrolujeme sockety, porty a pravidla firewallu, aby žádný přístup k FastCGI nebyl dostupný zvenčí.
- Záplatovat a uklidit: Aktualizujeme PHP a ukončíme všechny staré procesy, i osiřelé instance php-cgi.
- Nahradit: V rámci zpevnění serveru nahradíme zděděné CGI řešením PHP-FPM s vlastními pooly.
Časté dotazy
Je FastCGI totéž co PHP-FPM?
Ne. FastCGI je protokol, kterým webový server komunikuje s procesem aplikace. PHP-FPM je program, který tento protokol pro PHP realizuje a spravuje procesy. I php-cgi umí FastCGI, ale nenabízí pooly.
Proč se čisté CGI považuje za zastaralé?
U CGI spouští webový server pro každý požadavek nový proces a PHP při tom pokaždé čte svou konfiguraci. To stojí čas a zdroje. FastCGI a PHP-FPM drží procesy trvale připravené a jsou proto výrazně efektivnější.
Co je .user.ini?
Soubor .user.ini je malý konfigurační soubor ve webovém adresáři. Podle příručky PHP jej čtou jen SAPI CGI a FastCGI, tedy i PHP-FPM. Smí obsahovat pouze nastavení s režimy INI_PERDIR, INI_USER nebo INI_ALL.
Jak poznám, zda na mém serveru běží php-cgi?
Pomocí příkazů jen pro čtení, jako jsou ps nebo pgrep, vyhledejte procesy s názvem php-cgi a v konfiguraci webového serveru hledejte položky jako mod_fcgid, Action nebo ScriptAlias s php-cgi. V hostingových panelech se provozní režim často jmenuje CGI nebo aplikace FastCGI.