Εν ολίγοις: Σε έναν ζωντανό ιστότοπο το display_errors = Off ανήκει στο php.ini, μαζί με display_startup_errors = Off, log_errors = On και ένα log σφαλμάτων εκτός του webroot. Επιπλέον, τα CMS και τα frameworks πρέπει να εκτελούνται σε λειτουργία παραγωγής, αλλιώς οι δικές τους σελίδες σφαλμάτων δείχνουν τις λεπτομέρειες. Κλειδωμένα με php_admin_flag και ελεγμένα μετά από κάθε ενημέρωση, τα σφάλματα μένουν στο log αντί για τον περιηγητή.
Τι αποκαλύπτει ένα μόνο μήνυμα σφάλματος
Μια προειδοποίηση στο πάνω μέρος της σελίδας, ένα «Fatal error» αντί για την επισκόπηση παραγγελίας: τέτοιες εξόδους φαίνονται αθώες. Για έναν επιτιθέμενο είναι χάρτης. Δείχνουν πλήρεις διαδρομές αρχείων, ονόματα βάσεων δεδομένων και πινάκων, χρησιμοποιούμενες βιβλιοθήκες και συχνά την έκδοση PHP.
Ιδίως σε καταστάσεις όπως το PHP2Shell, όπου αναζητούνται μαζικά ευάλωτοι διακομιστές, ένας διακομιστής πρέπει να αποκαλύπτει όσο το δυνατόν λιγότερα για τον εαυτό του. Αυτό δεν κλείνει καμία ευπάθεια στον διερμηνέα PHP, δυσκολεύει όμως κάθε περαιτέρω βήμα μετά από μια εισβολή και κάνει πιο κοπιαστικές τις στοχευμένες επιθέσεις στην εφαρμογή σας.
Προστίθεται και η προστασία δεδομένων. Τα μηνύματα σφάλματος μπορεί να περιέχουν τμήματα αιτημάτων, για παράδειγμα διευθύνσεις email από φόρμες. Ό,τι εμφανίζεται στον περιηγητή ενός επισκέπτη δεν βρίσκεται πια υπό τον έλεγχό σας.
Οι προεπιλεγμένες τιμές δεν προορίζονται για την παραγωγή
Πολλοί υποθέτουν ότι η PHP αποκρύπτει μόνη της τα σφάλματα. Το εγχειρίδιο της PHP λέει κάτι άλλο: η ενσωματωμένη προεπιλεγμένη τιμή του display_errors είναι 1 και το display_startup_errors είναι από την PHP 8.0 επίσης ενεργοποιημένο από προεπιλογή. Μόνο το πρότυπο php.ini-production που συνοδεύει την PHP ορίζει και τα δύο σε Off. Το εγχειρίδιο αποκαλεί το display_errors ρητά λειτουργία ανάπτυξης, που δεν πρέπει να χρησιμοποιείται ποτέ σε συστήματα στο διαδίκτυο.
Το αν ο διακομιστής σας χρησιμοποιεί το πρότυπο παραγωγής δεν είναι αυτονόητο. Οι εικόνες container ξεκινούν εν μέρει χωρίς καθόλου php.ini, οι πίνακες ελέγχου φιλοξενίας ορίζουν δικές τους τιμές και μετά από μετακόμιση αντιγράφεται συχνά το πρότυπο ανάπτυξης.
display_errors off: οι ρυθμίσεις με μια ματιά
Οι παρακάτω τιμές είναι λογικές για διακομιστές παραγωγής. Οι σταθερές όπως το E_ALL λειτουργούν μόνο στο php.ini· στη διαμόρφωση του Apache δεν έχουν σύμφωνα με το εγχειρίδιο της PHP κανένα νόημα και πρέπει να δίνονται ως αριθμός.
| Ρύθμιση | Παραγωγή | Σκοπός |
|---|---|---|
display_errors |
Off |
κανένα σφάλμα στον περιηγητή |
display_startup_errors |
Off |
κανένα σφάλμα κατά την εκκίνηση της PHP στην έξοδο |
log_errors |
On |
εγγραφή των σφαλμάτων στο πρωτόκολλο |
error_log |
διαδρομή εκτός του webroot | ξεχωριστό αρχείο log ανά ιστότοπο ή pool |
error_reporting |
E_ALL |
καταγραφή όλων των σφαλμάτων, όχι εμφάνιση |
html_errors |
Off |
απλό κείμενο αντί για HTML στα πρωτόκολλα |
zend.exception_ignore_args |
On |
κανένα όρισμα συναρτήσεων στα stack traces |
fatal_error_backtraces |
0 μέχρι την ενημέρωση (μόνο PHP 8.5) |
μεταβατικό μέτρο σύμφωνα με το php.net |
Το zend.exception_ignore_args είναι ιδιαίτερα πολύτιμο. Χωρίς αυτή τη ρύθμιση, τα stack traces σε logs και σελίδες σφαλμάτων μπορούν να περιέχουν τα ορίσματα κλήσεων συναρτήσεων, άρα και κωδικούς ή tokens που μόλις επεξεργάζονταν.
; php.ini του 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
; μόνο PHP 8.5, μεταβατικό μέτρο μέχρι την ενημέρωση σε 8.5.12:
; fatal_error_backtraces = 0
Στο pool FPM κλειδώνετε επιπλέον τις σημαντικότερες τιμές, ώστε καμία εφαρμογή να μην μπορεί να τις ενεργοποιήσει ξανά με ini_set():
; π.χ. /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
Στη συνέχεια επανεκκινήστε την αντίστοιχη υπηρεσία PHP. Πώς ακριβώς λειτουργεί το κλείδωμα, εξηγεί το άρθρο php_admin_value: κλείδωμα ρυθμίσεων κατά της αντικατάστασης. Μια πλήρη βασική διαμόρφωση θα βρείτε στο Ασφαλής διαμόρφωση του php.ini.
Ο δεύτερος διακόπτης: λειτουργία debug της εφαρμογής
Η PHP είναι μόνο το μισό της δουλειάς. Τα σύγχρονα frameworks πιάνουν μόνα τους τα σφάλματα και δείχνουν δικές τους, συχνά πολύ αναλυτικές σελίδες σφαλμάτων. Στη λειτουργία debug περιέχουν αποσπάσματα πηγαίου κώδικα, τιμές διαμόρφωσης και κάποτε μεταβλητές περιβάλλοντος. Αυτές οι σελίδες εμφανίζονται ακόμη και όταν το display_errors στην PHP είναι απενεργοποιημένο.
Ελέγξτε γι' αυτό για κάθε εφαρμογή τον δικό της διακόπτη. Στο WordPress αυτά είναι τα WP_DEBUG και WP_DEBUG_DISPLAY στο wp-config.php, στο Laravel και στο Symfony το APP_DEBUG και το περιβάλλον στο αρχείο .env, σε άλλα συστήματα η λειτουργία παραγωγής σύμφωνα με την τεκμηρίωση του κατασκευαστή. Σε ένα ζωντανό σύστημα η λειτουργία debug πρέπει να είναι μόνιμα εκτός, ακόμη και «μόνο για λίγο για δοκιμή» είναι κίνδυνος.
Πώς χειρίζεται σωστά η εφαρμογή τα σφάλματα, αντί να τα καταστέλλει, περιγράφει το Σφάλματα και εξαιρέσεις στην PHP.
Έτσι βρίσκετε εξόδους σφαλμάτων προτού τις βρουν άλλοι
Δεν αρκεί να το ρυθμίσετε μία φορά. Οι έξοδοι σφαλμάτων επιστρέφουν μετά από ενημερώσεις, μετακομίσεις ή αλλαγές στον πίνακα ελέγχου. Μια σύντομη διαδικασία ελέγχου βοηθά:
- Ελέγξτε τις αποτελεσματικές τιμές στο πλαίσιο του web, όχι μόνο στη γραμμή εντολών, για παράδειγμα με ένα αρχείο ελέγχου που τοποθετείται για λίγο και διαγράφεται αμέσως μετά.
- Ελέγξτε τη λειτουργία debug κάθε εφαρμογής στο δικό της αρχείο διαμόρφωσης.
- Ψάξτε τις σελίδες που σερβίρονται για τυπικά κείμενα σφαλμάτων, όπως στο παρακάτω μπλοκ κώδικα.
- Στη μηχανή αναζήτησης αναζητήστε με ερώτημα
site:στο domain σας όρους όπως «Fatal error» ή «Warning». - Ελέγξτε αν γράφεται το log σφαλμάτων και ότι δεν βρίσκεται στο webroot.
# Αναζήτηση κειμένων σφαλμάτων PHP στις σελίδες που σερβίρονται (μόνο δικά σας domains)
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
# Γράφεται το log σφαλμάτων;
ls -l /var/log/php/
Η απόκρυψη των σφαλμάτων δεν αντικαθιστά τη διόρθωσή τους. Ένα log γεμάτο προειδοποιήσεις είναι ένδειξη ανάγκης συντήρησης και μετά από μια εισβολή είναι συχνά ένα σημαντικό ίχνος. Τι καταγράφετε και τι όχι, περιγράφει το Ασφαλής καταγραφή: καταγραφή σφαλμάτων χωρίς διαρροή δεδομένων.
Συμπέρασμα: σιωπηλά στον περιηγητή, ομιλητικά στο log
Ο κανόνας για διακομιστές παραγωγής είναι απλός: τα σφάλματα ανήκουν στο πρωτόκολλο και όχι στον ιστότοπο. Στην πράξη αποτυγχάνει εξαιτίας προεπιλεγμένων τιμών που δεν προορίζονται για την παραγωγή, διακοπτών debug σε εφαρμογές και διαμορφώσεων που υποχωρούν μετά από ενημερώσεις ή μετακομίσεις.
Όποιος απενεργοποιεί τα display_errors και display_startup_errors, κλειδώνει τις τιμές στο pool, ελέγχει τη λειτουργία debug της εφαρμογής και επαληθεύει τακτικά το αποτέλεσμα, κλείνει μία από τις συχνότερες πηγές περιττής αποκάλυψης πληροφοριών. Η προσπάθεια είναι μικρή, το αποτέλεσμα διαρκεί, εφόσον ο έλεγχος παραμένει μέρος κάθε ενημέρωσης.
Ένα σημείο δεν πρέπει να χαθεί: το log σφαλμάτων δεν είναι κάδος απορριμμάτων. Όποιος το διαβάζει τακτικά αναγνωρίζει ελαττωματικές ενημερώσεις, παρωχημένες συναρτήσεις και κάποτε τα πρώτα ίχνη μιας επίθεσης, πολύ πριν αντιληφθούν κάτι οι πελάτες.
Πώς βοηθά συγκεκριμένα η PHP SOS;
- Έλεγχος: Διαβάζουμε τις αποτελεσματικές ρυθμίσεις σφαλμάτων ανά ιστότοπο και pool και ψάχνουμε τις σελίδες που σερβίρονται για εξόδους σφαλμάτων.
- Μετάβαση: Ορίζουμε ρυθμίσεις PHP και εφαρμογής για τη λειτουργία παραγωγής και τις κλειδώνουμε κατά της αντικατάστασης.
- Στήσιμο πρωτοκόλλων: Τα logs σφαλμάτων βρίσκονται εκτός του webroot, περιστρέφονται και είναι προσβάσιμα στους προγραμματιστές σας.
- Διατήρηση μόνιμα: Στη σύμβαση συντήρησης ασφαλείας ελέγχουμε ξανά τις ρυθμίσεις μετά από κάθε ενημέρωση.
Συχνές ερωτήσεις
Δεν είναι ήδη απενεργοποιημένο το display_errors στην PHP;
Όχι αυτόματα. Σύμφωνα με το εγχειρίδιο της PHP, η ενσωματωμένη προεπιλεγμένη τιμή του display_errors είναι 1. Μόνο το πρότυπο php.ini-production που συνοδεύει την PHP ορίζει Off. Το αν ο διακομιστής σας χρησιμοποιεί αυτό το πρότυπο εξαρτάται από τη διανομή, τον πίνακα ελέγχου ή την εικόνα container και πρέπει να ελεγχθεί.
Αρκεί το display_errors = Off όταν το WordPress ή το Laravel εκτελούνται σε λειτουργία debug;
Όχι. Πολλά CMS και frameworks διαθέτουν δικές τους σελίδες σφαλμάτων, που μπορούν να εμφανίζουν λεπτομέρειες ανεξάρτητα από την PHP. Απενεργοποιήστε γι' αυτό και τη λειτουργία debug της εφαρμογής, για παράδειγμα WP_DEBUG_DISPLAY στο WordPress ή APP_DEBUG στο Laravel και στο Symfony.
Πού πηγαίνουν τα σφάλματα όταν δεν εμφανίζονται πια;
Με log_errors = On η PHP τα γράφει στο αρχείο που ορίζει το error_log ή στο πρωτόκολλο του εκάστοτε τρόπου λειτουργίας, για παράδειγμα στο log σφαλμάτων του Apache ή του PHP-FPM. Το αρχείο πρέπει να βρίσκεται εκτός του webroot και να περιστρέφεται τακτικά.
Τι σχέση έχει το fatal_error_backtraces με το PHP2Shell;
Η ρύθμιση υπάρχει από την PHP 8.5 και είναι από προεπιλογή ενεργή. Το php.net αναφέρει το fatal_error_backtraces=0 με επακόλουθη επανεκκίνηση ως ένα από τα μεταβατικά μέτρα για την PHP 8.5, όσο εκκρεμεί η ενημέρωση σε 8.5.12. Δεν αντικαθιστά την ενημέρωση.