Īsi sakot: Dzīvā vietnē display_errors = Off pieder failā php.ini kopā ar display_startup_errors = Off, log_errors = On un kļūdu žurnālu ārpus tīmekļa saknes. Turklāt CMS un ietvariem jādarbojas produkcijas režīmā, citādi to pašu kļūdu lapas rāda detaļas. Nobloķējot ar php_admin_flag un pārbaudot pēc katra atjauninājuma, kļūdas paliek žurnālā, nevis pārlūkā.
Ko atklāj viens kļūdas ziņojums
Brīdinājums lapas augšmalā, „Fatal error" pasūtījuma pārskata vietā: šādi izvadi izskatās nekaitīgi. Uzbrucējam tie ir karte. Tie rāda pilnus failu ceļus, datubāzu un tabulu nosaukumus, izmantotās bibliotēkas un bieži PHP versiju.
Tieši tādās situācijās kā PHP2Shell, kad masveidā meklē ievainojamus serverus, serverim jāatklāj pēc iespējas mazāk. Tas neaizver nevienu ievainojamību PHP interpretatorā, bet apgrūtina katru turpmāko soli pēc ielaušanās un padara mērķtiecīgus uzbrukumus jūsu lietojumprogrammai grūtākus.
Pievienojas datu aizsardzība. Kļūdu ziņojumi var saturēt pieprasījumu daļas, piemēram, e-pasta adreses no veidlapām. Kas parādās apmeklētāja pārlūkā, vairs nav jūsu kontrolē.
Noklusējuma vērtības nav paredzētas produkcijai
Daudzi pieņem, ka PHP kļūdas slēpj pats. PHP rokasgrāmata saka ko citu: iebūvētā display_errors noklusējuma vērtība ir 1, un display_startup_errors kopš PHP 8.0 arī pēc noklusējuma ir ieslēgts. Tikai komplektā iekļautā veidne php.ini-production abus iestata uz Off. Rokasgrāmata display_errors nepārprotami sauc par izstrādes funkciju, kuru sistēmās internetā nekad nedrīkst izmantot.
Vai jūsu serveris izmanto produkcijas veidni, nav pašsaprotami. Konteineru attēli dažkārt startē pavisam bez php.ini, hostinga paneļi iestata savas vērtības, un pēc pārcelšanās labprāt tiek nokopēta izstrādes veidne.
display_errors off: iestatījumu pārskats
Turpmākās vērtības ir saprātīgas produkcijas serveriem. Konstantes, piemēram, E_ALL, darbojas tikai php.ini; Apache konfigurācijā tām saskaņā ar PHP rokasgrāmatu nav nozīmes, un tās jānorāda kā skaitlis.
| Iestatījums | Produkcija | Mērķis |
|---|---|---|
display_errors |
Off |
nekādu kļūdu pārlūkā |
display_startup_errors |
Off |
nekādu PHP startēšanas kļūdu izvadē |
log_errors |
On |
kļūdas ierakstīt protokolā |
error_log |
ceļš ārpus tīmekļa saknes | savs žurnāla fails katrai vietnei vai pūlam |
error_reporting |
E_ALL |
protokolēt visas kļūdas, nerādīt |
html_errors |
Off |
vienkāršs teksts HTML vietā protokolos |
zend.exception_ignore_args |
On |
funkciju argumenti stack trace neparādās |
fatal_error_backtraces |
0 līdz atjauninājumam (tikai PHP 8.5) |
pārejas pasākums saskaņā ar php.net |
zend.exception_ignore_args ir īpaši vērtīgs. Bez šī iestatījuma stack trace žurnālos un kļūdu lapās var saturēt funkciju izsaukumu argumentus, tātad arī paroles vai tokenus, kas tikko tika apstrādāti.
; tīmekļa SAPI php.ini
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
; tikai PHP 8.5, pārejas pasākums līdz atjauninājumam uz 8.5.12:
; fatal_error_backtraces = 0
FPM pūlā svarīgākās vērtības papildus nobloķējiet, lai neviena lietojumprogramma tās ar ini_set() neieslēgtu atpakaļ:
; piem., /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
Pēc tam attiecīgo PHP pakalpojumu pārstartējiet. Kā tieši darbojas bloķēšana, izskaidro raksts php_admin_value: iestatījumu bloķēšana pret pārrakstīšanu. Pilnu pamata konfigurāciju atradīsit sadaļā php.ini droša konfigurēšana.
Otrs slēdzis: lietojumprogrammas atkļūdošanas režīms
PHP ir tikai puse darba. Mūsdienīgi ietvari kļūdas pārtver paši un rāda savas, bieži ļoti izsmeļošas kļūdu lapas. Atkļūdošanas režīmā tajās ir pirmkoda izraksti, konfigurācijas vērtības un dažkārt vides mainīgie. Šīs lapas parādās arī tad, ja display_errors PHP ir izslēgts.
Tāpēc katrai lietojumprogrammai pārbaudiet tās pašas slēdzi. WordPress tie ir WP_DEBUG un WP_DEBUG_DISPLAY failā wp-config.php, Laravel un Symfony APP_DEBUG un vide failā .env, citām sistēmām produkcijas režīms saskaņā ar ražotāja dokumentāciju. Dzīvā sistēmā atkļūdošanas režīmam jābūt izslēgtam pastāvīgi, arī „tikai uz brīdi testēšanai" ir risks.
Kā kļūdas lietojumprogrammā sakārtoti apstrādāt, nevis tās apslāpēt, apraksta Kļūdas un izņēmumi PHP.
Kā atrast kļūdu izvadi, pirms to izdara citi
Vienreiz iestatīt nepietiek. Kļūdu izvade atgriežas pēc atjauninājumiem, pārcelšanās vai paneļa izmaiņām. Palīdz īsa pārbaudes gaita:
- Spēkā esošās vērtības pārbaudīt tīmekļa kontekstā, ne tikai komandrindā, piemēram, ar īslaicīgi novietotu, pēc tam nekavējoties izdzēstu pārbaudes failu.
- Katras lietojumprogrammas atkļūdošanas režīmu pārbaudīt tās konfigurācijas failā.
- Piegādātās lapas pārmeklēt pēc tipiskiem kļūdu tekstiem, kā norādīts zemāk esošajā koda blokā.
- Meklētājprogrammā ar
site:vaicājumu uz savu domēnu meklēt tādus jēdzienus kā „Fatal error" vai „Warning". - Pārbaudīt, vai kļūdu žurnālā tiek rakstīts un vai tas neatrodas tīmekļa saknē.
# Piegādātās lapas pārmeklēt pēc PHP kļūdu tekstiem (tikai savi domēni)
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
# Vai kļūdu žurnālā tiek rakstīts?
ls -l /var/log/php/
Kļūdu slēpšana neaizstāj to novēršanu. Žurnāls, pilns ar brīdinājumiem, ir norāde uz uzturēšanas vajadzību, un pēc ielaušanās tas bieži ir svarīga pēda. Ko pie tam protokolēt un ko ne, apraksta Droša protokolēšana: kļūdu ierakstīšana bez datu noplūdes.
Secinājums: kluss pārlūkā, runīgs žurnālā
Noteikums produkcijas serveriem ir vienkāršs: kļūdām jāatrodas protokolā, nevis vietnē. Praksē tas izgāžas uz noklusējuma vērtībām, kas nav paredzētas produkcijai, uz atkļūdošanas slēdžiem lietojumprogrammās un uz konfigurācijām, kas pēc atjauninājumiem vai pārcelšanās atgriežas iepriekšējā stāvoklī.
Kas izslēdz display_errors un display_startup_errors, nobloķē vērtības pūlā, pārbauda lietojumprogrammas atkļūdošanas režīmu un rezultātu regulāri pārbauda, tas aizver vienu no biežākajiem nevajadzīgas informācijas atklāšanas avotiem. Piepūle ir neliela, ietekme noturīga, kamēr pārbaude paliek katra atjauninājuma sastāvdaļa.
Vienu punktu nevajadzētu aizmirst: kļūdu žurnāls nav atkritumu tvertne. Kas to regulāri lasa, tas atpazīst kļūdainus atjauninājumus, novecojušas funkcijas un dažkārt arī pirmās uzbrukuma pēdas, ilgi pirms klienti kaut ko pamana.
Kā PHP SOS palīdz konkrēti?
- Pārbaudīt: mēs nolasām spēkā esošos kļūdu iestatījumus katrai vietnei un pūlam un pārmeklējam piegādātās lapas, meklējot kļūdu izvadi.
- Pārslēgt: mēs iestatām PHP un lietojumprogrammu iestatījumus produkcijas darbībai un nobloķējam tos pret pārrakstīšanu.
- Ieviest protokolus: kļūdu žurnāli atrodas ārpus tīmekļa saknes, tiek rotēti un ir pieejami jūsu izstrādātājiem.
- Noturēt pastāvīgi: drošības uzturēšanas līgumā mēs iestatījumus pēc katra atjauninājuma pārbaudām atkārtoti.
Biežāk uzdotie jautājumi
Vai display_errors PHP tāpat nav izslēgts?
Ne automātiski. Saskaņā ar PHP rokasgrāmatu iebūvētā display_errors noklusējuma vērtība ir 1. Tikai komplektā iekļautā veidne php.ini-production iestata Off. Vai jūsu serveris šo veidni izmanto, atkarīgs no distributīva, paneļa vai konteinera attēla, un tas jāpārbauda.
Vai pietiek ar display_errors = Off, ja WordPress vai Laravel darbojas atkļūdošanas režīmā?
Nē. Daudzi CMS un ietvari nāk ar savām kļūdu lapām, kas neatkarīgi no PHP var rādīt detaļas. Tāpēc izslēdziet arī lietojumprogrammas atkļūdošanas režīmu, piemēram, WP_DEBUG_DISPLAY WordPress vai APP_DEBUG Laravel un Symfony.
Kurp nonāk kļūdas, ja tās vairs netiek rādītas?
Ar log_errors = On PHP tās ieraksta failā, ko nosauc error_log, vai attiecīgā darbības režīma žurnālā, piemēram, Apache vai PHP-FPM kļūdu žurnālā. Failam jāatrodas ārpus tīmekļa saknes un tas regulāri jārotē.
Ko fatal_error_backtraces kopīga ar PHP2Shell?
Iestatījums pastāv kopš PHP 8.5 un pēc noklusējuma ir aktīvs. php.net min fatal_error_backtraces=0 ar sekojošu pārstartēšanu kā vienu no pārejas pasākumiem PHP 8.5, kamēr atjauninājums uz 8.5.12 vēl nav veikts. Tas neaizstāj atjauninājumu.