Stručně: mod_php je PHP jako modul ve webovém serveru Apache. Každý proces Apache pak obsahuje úplný interpret PHP a kód PHP provádí sám; SAPI se jmenuje apache2handler. Je to jednoduché na zřízení, ale PHP to váže na Apache, většinou to vyžaduje MPM prefork a téměř to neumožňuje oddělení webů. Příručka PHP pro nové instalace odrazuje a u PHP2Shell hodnotí tým PHP riziko u mod_php nejvýše.
Co je mod_php?
U mod_php Apache načítá PHP jako vlastní modul do svých procesů. Neexistuje oddělená služba PHP: když má Apache vydat soubor .php, provede kód PHP tentýž proces, který požadavek přijal. Mnoho let to byl standardní způsob provozu PHP a na starších serverech a v některých image Dockeru je rozšířený dodnes.
Podle příručky PHP čte PHP jako serverový modul svou konfiguraci jen jednou, při spuštění webového serveru. Změny v php.ini a aktualizace modulu proto působí až po restartu Apache.
Důležité pro porozumění: procesy Apache žijí dlouho. Jeden proces přijímá postupně mnoho spojení, než je nahrazen; kolik, řídí direktiva Apache MaxConnectionsPerChild. Vložený interpret PHP zůstává po tuto dobu tentýž. Kdo vymění knihovnu libphp na disku, na běžících procesech nic nezmění.
Pro jednatele a projektové vedoucí lze shrnout: u mod_php tvoří webový server a PHP jednotu. Kdo sáhne na jedno, ovlivní druhé. Aktualizace PHP znamená restart webového serveru, chyba v PHP běží s oprávněními webového serveru a oddělení více webů na stejném serveru je téměř nemožné.
Jak se mod_php začleňuje?
Příručka PHP ukazuje začlenění ve dvou krocích: načíst modul a určit, které soubory má PHP zpracovávat.
LoadModule php_module modules/libphp.so
<FilesMatch \.php$>
SetHandler application/x-httpd-php
</FilesMatch>
Příručka doporučuje FilesMatch se SetHandler místo pouhého AddType, aby se nahrané soubory jako bild.php.jpg neprováděly jako PHP. V Debianu a Ubuntu tuto práci obstarávají balíčky jako libapache2-mod-php8.3 a příkazy a2enmod a a2dismod.
Zda je mod_php aktivní, lze ověřit jen čtením:
apachectl -M 2>/dev/null | grep -i php # Debian/Ubuntu
httpd -M 2>/dev/null | grep -i php # rodina RHEL
apachectl -V | grep -i mpm # aktivní MPM (prefork, worker, event)
Prefork, Thread Safety a zdroje
Apache rozděluje požadavky přes modul Multi-Processing (MPM). Podle příručky PHP vyžaduje mod_php MPM prefork, pokud nebylo PHP sestaveno se Zend Thread Safety (--enable-zts). Většina balíčků distribucí je sestavena bez Thread Safety.
Prefork znamená: jeden proces na souběžné spojení a každý proces nese kompletní interpret PHP. I požadavky na obrázky nebo soubory CSS tak zabírají proces s PHP v zavazadlech. To stojí paměť a omezuje zátěž, kterou server unese.
| Vlastnost | mod_php | PHP-FPM |
|---|---|---|
| Kde běží PHP? | v každém procesu Apache | v samostatné službě |
| MPM Apache | většinou prefork |
možné event |
| Uživatel pro každý web | ne, vše jako uživatel Apache | ano, pro každý pool |
| Restart PHP | jen s Apache | nezávisle na Apache |
| Nastavení pro adresář | php_value v .htaccess |
pool nebo .user.ini |
Příručka proto pro všechny moderní instalace doporučuje PHP-FPM s mod_proxy_fcgi: lepší správu zdrojů, oddělení procesů, restart PHP bez restartu Apache a kompatibilitu s MPM event, který je od Apache 2.4 výchozí. Základy popisuje článek PHP-FPM vysvětleno.
Nastavení pomocí .htaccess, php_value a php_admin_value
S mod_php lze nastavení PHP provádět přímo v konfiguraci Apache. Příručka přitom rozlišuje režimy změn: položky s INI_PERDIR smějí být v php.ini, .htaccess nebo httpd.conf, položky s INI_SYSTEM jen v php.ini nebo httpd.conf.
# V konfiguraci VirtualHost: pro aplikaci uzamčeno
php_admin_flag display_errors off
php_admin_value upload_max_filesize 24M
# Možné v .htaccess, ale aplikace to může přepsat
php_value max_execution_time 60
php_admin_value a php_admin_flag jsou povoleny jen v konfiguraci serveru, nikoli v .htaccess. Právě toto rozlišení je důležité u přechodných opatření k PHP2Shell, protože hodnoty jako session.upload_progress.enabled nesmí aplikace vrátit zpět.
mod_php a PHP2Shell: proč je riziko nejvyšší
Tým PHP hodnotí riziko ze zranitelnosti PHP2Shell u mod_php nejvýše: tam byl předveden exploit dříve, než se vůbec spustí kód aplikace. Bezpečnostní pluginy nebo kontroly v CMS tak přicházejí pozdě. K tomu přistupuje, že PHP u mod_php běží s oprávněními a v paměti webového serveru. Podrobné zařazení najdete v článku Proč nese mod_php nejvyšší riziko.
Pro provozovatele proto platí:
- Aktualizovat modul PHP na 8.5.12, 8.4.27, 8.3.36 nebo 8.2.35, případně na potvrzený backport.
- Apache restartovat úplně, nikoli jen znovu načíst, a zkontrolovat dobu spuštění procesů.
- Přechodné hodnoty nastavit přes
php_admin_valuev konfiguraci serveru, pokud aktualizace ještě není možná. - Poté naplánovat přechod na PHP-FPM, jak popisuje článek Zabezpečení Apache s mod_php.
Jak konkrétně pomáhá PHP SOS?
- Rozpoznat: Zjistíme, na kterých serverech běží mod_php, s jakým MPM a z jakého zdroje balíčků.
- Záplatovat: Aktualizujeme modul PHP, úplně restartujeme Apache a doložíme stav.
- Zajistit přechodné období: Tam, kde je aktualizace blokována, nastavíme opatření z php.net jako uzamčená v konfiguraci serveru.
- Přejít: V rámci zpevnění serveru provedeme otestovanou migraci na PHP-FPM s vlastními pooly.
Časté dotazy
Proč se říká mod_php, když se modul jmenuje php_module?
mod_php je hovorový název pro PHP jako modul Apache. V konfiguraci se načítá pomocí LoadModule; příručka PHP uvádí jako příklad LoadModule php_module modules/libphp.so. Starší verze používaly názvy jako php7_module nebo php5_module.
Proč mod_php potřebuje MPM prefork?
Podle příručky PHP vyžaduje mod_php MPM prefork, pokud nebylo PHP sestaveno se Zend Thread Safety. Většina balíčků distribucí je sestavena bez Thread Safety. Prefork spouští pro každé souběžné spojení vlastní proces, což potřebuje více paměti.
Fungují řádky php_value v .htaccess i s PHP-FPM?
Ne. php_value a php_flag v .htaccess jsou direktivy Apache modulu PHP a působí jen s mod_php. U PHP-FPM patří taková nastavení do poolu nebo, pro povolené hodnoty, do .user.ini.
Musím mod_php okamžitě opustit?
Nejprve přichází aktualizace PHP s úplným restartem Apache. Přechod na PHP-FPM je poté rozumný, měl by být ale naplánován a otestován. PHP2Shell neuzavře, protože PHP-FPM je postiženo rovněž.