Stručně: Na ostrém webu patří display_errors = Off do php.ini, spolu s display_startup_errors = Off, log_errors = On a chybovým logem mimo webroot. CMS a frameworky navíc musí běžet v produkčním režimu, jinak podrobnosti ukazují jejich vlastní chybové stránky. Uzamčeno pomocí php_admin_flag a po každé aktualizaci ověřeno, zůstávají chyby v logu místo v prohlížeči.
Co prozradí jediné chybové hlášení
Varování v horním okraji stránky, „Fatal error“ místo přehledu objednávky: takové výstupy vypadají neškodně. Pro útočníka jsou mapou. Ukazují úplné cesty k souborům, názvy databází a tabulek, použité knihovny a často i verzi PHP.
Právě v situacích jako PHP2Shell, kdy se masivně hledají zranitelné servery, by server měl o sobě prozrazovat co nejméně. Žádnou mezeru v interpretu PHP to neuzavře, ale ztíží to každý další krok po průniku a cílené útoky na vaši aplikaci to činí namáhavějšími.
K tomu přistupuje ochrana osobních údajů. Chybová hlášení mohou obsahovat části požadavků, například e-mailové adresy z formulářů. Co se objeví v prohlížeči návštěvníka, už nemáte pod kontrolou.
Výchozí hodnoty nejsou určeny pro produkci
Mnozí předpokládají, že PHP chyby samo skrývá. Příručka PHP říká něco jiného: vestavěná výchozí hodnota display_errors je 1 a display_startup_errors je od PHP 8.0 rovněž standardně zapnuto. Teprve dodávaná šablona php.ini-production obojí nastavuje na Off. Příručka označuje display_errors výslovně za vývojovou funkci, která by se na systémech v internetu nikdy neměla používat.
Zda váš server používá produkční šablonu, není samozřejmé. Image kontejnerů někdy startují zcela bez php.ini, hostingové panely nastavují vlastní hodnoty a po přestěhování se rádo zkopíruje vývojová šablona.
display_errors off: přehled nastavení
Následující hodnoty jsou pro produkční servery rozumné. Konstanty jako E_ALL fungují jen v php.ini; v konfiguraci Apache nemají podle příručky PHP význam a je nutné je zadat jako číslo.
| Nastavení | Produkce | Účel |
|---|---|---|
display_errors |
Off |
žádné chyby v prohlížeči |
display_startup_errors |
Off |
žádné chyby při startu PHP ve výstupu |
log_errors |
On |
zapisovat chyby do protokolu |
error_log |
cesta mimo webroot | vlastní logovací soubor pro každý web nebo pool |
error_reporting |
E_ALL |
protokolovat všechny chyby, nezobrazovat |
html_errors |
Off |
prostý text místo HTML v protokolech |
zend.exception_ignore_args |
On |
žádné argumenty funkcí ve stack trace |
fatal_error_backtraces |
0 do aktualizace (jen PHP 8.5) |
přechodné opatření podle php.net |
zend.exception_ignore_args je zvlášť cenné. Bez tohoto nastavení mohou stack trace v lozích a na chybových stránkách obsahovat argumenty volání funkcí, tedy i hesla nebo tokeny, které se právě zpracovávaly.
; php.ini webového SAPI
display_errors = Off
display_startup_errors = Off
log_errors = On
error_log = /var/log/php/website-fehler.log
error_reporting = E_ALL
html_errors = Off
zend.exception_ignore_args = On
; jen PHP 8.5, přechodné opatření do aktualizace na 8.5.12:
; fatal_error_backtraces = 0
V poolu FPM nejdůležitější hodnoty navíc uzamkněte, aby je žádná aplikace pomocí ini_set() nezapnula zpět:
; např. /etc/php/8.3/fpm/pool.d/seite1.conf
php_admin_flag[display_errors] = off
php_admin_flag[display_startup_errors] = off
php_admin_flag[log_errors] = on
php_admin_value[error_log] = /var/log/php/seite1-fehler.log
Poté restartujte příslušnou službu PHP. Jak přesně uzamykání funguje, vysvětluje článek php_admin_value: uzamknutí nastavení proti přepsání. Úplnou základní konfiguraci najdete v článku Bezpečná konfigurace php.ini.
Druhý přepínač: ladicí režim aplikace
PHP je jen polovina práce. Moderní frameworky chyby zachytávají samy a zobrazují vlastní, často velmi podrobné chybové stránky. V ladicím režimu obsahují výňatky ze zdrojového kódu, hodnoty konfigurace a někdy i proměnné prostředí. Tyto stránky se zobrazí i tehdy, když je display_errors v PHP vypnuto.
Zkontrolujte proto u každé aplikace její vlastní přepínač. U WordPressu jsou to WP_DEBUG a WP_DEBUG_DISPLAY v wp-config.php, u Laravelu a Symfony APP_DEBUG a prostředí v souboru .env, u jiných systémů produkční režim podle dokumentace výrobce. Na ostrém systému patří ladicí režim trvale vypnout, i „jen na chvíli k testování“ je riziko.
Jak se s chybami v aplikaci zachází čistě, místo aby se potlačovaly, popisuje Chyby a výjimky v PHP.
Jak najít chybové výstupy dříve než ostatní
Jednorázové nastavení nestačí. Chybové výstupy se po aktualizacích, stěhováních nebo změnách v panelu vracejí. Pomůže krátký kontrolní postup:
- Zkontrolovat platné hodnoty z webu, nejen z příkazové řádky, například krátce umístěným a ihned smazaným kontrolním souborem.
- Zkontrolovat ladicí režim každé aplikace v jejím konfiguračním souboru.
- Prohledat doručené stránky na typické texty chyb, jak ukazuje blok kódu níže.
- Ve vyhledávači pomocí dotazu
site:na vaši doménu hledat výrazy jako „Fatal error“ nebo „Warning“. - Ověřit, že se do chybového logu zapisuje a že neleží ve webrootu.
# Prohledat doručené stránky na texty chyb PHP (jen vlastní domény)
for url in https://www.example.de/ https://www.example.de/kontakt/; do
curl -s "$url" | grep -E -o "(Fatal error|Warning|Notice|Deprecated|Stack trace)[^<]{0,80}" | head -3
done
# Zapisuje se do chybového logu?
ls -l /var/log/php/
Skrývat chyby není náhradou za jejich odstranění. Log plný varování je upozornění na potřebu údržby a po průniku je často důležitou stopou. Co při tom protokolovat a co ne, popisuje Bezpečné logování: protokolovat chyby bez úniku dat.
Závěr: tiše v prohlížeči, hovorně v logu
Pravidlo pro produkční servery je jednoduché: chyby patří do protokolu, ne na web. V praxi selhává na výchozích hodnotách, které nejsou určeny pro produkci, na ladicích přepínačích v aplikacích a na konfiguracích, které se po aktualizacích nebo stěhováních vrátí zpět.
Kdo vypne display_errors a display_startup_errors, uzamkne hodnoty v poolu, zkontroluje ladicí režim aplikace a výsledek pravidelně ověřuje, uzavře jeden z nejčastějších zdrojů zbytečného úniku informací. Pracnost je nízká, účinek vydrží, dokud kontrola zůstává součástí každé aktualizace.
Jeden bod by neměl zapadnout: chybový log není odpadkový koš. Kdo jej pravidelně čte, pozná chybné aktualizace, zastaralé funkce a někdy i první stopy útoku, dlouho před tím, než si zákazníci něčeho všimnou.
Jak konkrétně pomáhá PHP SOS?
- Zkontrolovat: Načteme platná nastavení chyb pro každý web a pool a doručené stránky prohledáme na chybové výstupy.
- Přepnout: Nastavení PHP a aplikací nastavíme pro ostrý provoz a uzamkneme je proti přepsání.
- Zřídit protokoly: Chybové logy leží mimo webroot, rotují se a jsou přístupné vašim vývojářům.
- Udržet trvale: V rámci smlouvy o bezpečnostní údržbě nastavení po každé aktualizaci znovu zkontrolujeme.
Časté dotazy
Není display_errors v PHP stejně vypnuto?
Ne automaticky. Podle příručky PHP je vestavěná výchozí hodnota display_errors 1. Teprve dodávaná šablona php.ini-production nastavuje Off. Zda váš server tuto šablonu používá, závisí na distribuci, panelu nebo image kontejneru a je třeba to ověřit.
Stačí display_errors = Off, když WordPress nebo Laravel běží v ladicím režimu?
Ne. Mnoho CMS a frameworků má vlastní chybové stránky, které mohou zobrazovat podrobnosti nezávisle na PHP. Vypněte proto i ladicí režim aplikace, například WP_DEBUG_DISPLAY u WordPressu nebo APP_DEBUG u Laravelu a Symfony.
Kam jdou chyby, když se už nezobrazují?
S log_errors = On je PHP zapisuje do souboru, který určuje error_log, nebo do protokolu příslušného provozního režimu, například do chybového logu Apache nebo PHP-FPM. Soubor by měl ležet mimo webroot a pravidelně se rotovat.
Co má fatal_error_backtraces společného s PHP2Shell?
Nastavení existuje od PHP 8.5 a je standardně aktivní. php.net uvádí fatal_error_backtraces=0 s následným restartem jako jedno z přechodných opatření pro PHP 8.5, dokud aktualizace na 8.5.12 chybí. Aktualizaci nenahrazuje.