Τρέχουσα κατάσταση: PHP2Shell. Δύο κρίσιμες ευπάθειες της PHP (CVSS 9.2) επιτρέπουν κακόβουλο κώδικα χωρίς σύνδεση. Patches από τις 21/10/2026.Τι πρέπει να γίνει τώρα →

Επικύρωση και φιλτράρισμα εισόδου στην PHP με το filter_var

Πώς ελέγχουν οι προγραμματιστές την είσοδο στην PHP με τα filter_var, filter_input_array και λίστες επιτρεπόμενων τιμών, ποια φίλτρα είναι παρωχημένα και γιατί η επικύρωση δεν αντικαθιστά τα prepared statements και την κωδικοποίηση εξόδου.

Ημερομηνία 6 λεπτά ανάγνωσηςΑσφαλής ανάπτυξη

Εν ολίγοις: Την είσοδο στην PHP την επικυρώνετε με το filter_var() ή το filter_input_array() και σαφείς κανόνες ανά πεδίο: τύπος, εύρος, μήκος και επιτρεπόμενες τιμές. Ό,τι δεν ταιριάζει απορρίπτεται και δεν μετασχηματίζεται σιωπηλά. Η επικύρωση είναι σημαντική για καθαρά δεδομένα και μικρότερη επιφάνεια επίθεσης, δεν αντικαθιστά όμως ούτε τα prepared statements απέναντι στο SQL injection ούτε την κωδικοποίηση ανάλογα με το πλαίσιο απέναντι στο XSS.

Γιατί το «φιλτράρισμα των πάντων» δεν είναι στρατηγική

Σε πολλά παλαιότερα έργα PHP βρίσκεται στην αρχή κάθε αρχείου ένας βρόχος που περνά όλες τις τιμές των $_GET και $_POST μέσα από μια συνάρτηση καθαρισμού. Αυτό δίνει αίσθηση ασφάλειας. Στην πράξη αφαιρεί άλλοτε πάρα πολλά, για παράδειγμα αποστρόφους σε επώνυμα, και άλλοτε πολύ λίγα, επειδή η ίδια συνάρτηση πρέπει να ισχύει ταυτόχρονα για SQL, HTML και ονόματα αρχείων.

Η ουσιαστική επικύρωση λειτουργεί διαφορετικά: ρωτά για κάθε πεδίο τι επιτρέπεται εκεί. Μια ποσότητα παραγγελίας είναι ακέραιος αριθμός ανάμεσα στο 1 και ένα ανώτατο όριο. Ένα πεδίο ταξινόμησης είναι μία από τρεις σταθερές τιμές. Μια ημερομηνία έχει συγκεκριμένη μορφή και βρίσκεται πριν από μια άλλη ημερομηνία. Όλα τα άλλα απορρίπτονται.

Το OWASP διακρίνει εδώ δύο επίπεδα: τον συντακτικό έλεγχο, αν μια τιμή έχει τη σωστή μορφή, και τον σημασιολογικό έλεγχο, αν έχει νόημα στο πλαίσιό της. Και τα δύο ανήκουν στον διακομιστή· οι έλεγχοι στον browser εξυπηρετούν μόνο τη χρηστικότητα.

Ποια φίλτρα περιλαμβάνει η PHP

Η επέκταση φίλτρων περιλαμβάνεται εξ ορισμού στην PHP. Τα σημαντικότερα φίλτρα επικύρωσης σύμφωνα με το εγχειρίδιο της PHP:

Φίλτρο Ελέγχει Σημαντικές επιλογές και υποδείξεις
FILTER_VALIDATE_INT ακέραιο αριθμό min_range, max_range
FILTER_VALIDATE_FLOAT δεκαδικό αριθμό decimal για τον διαχωριστή
FILTER_VALIDATE_BOOL λογική τιμή με FILTER_NULL_ON_FAILURE διακρίνεται από το «ψευδές»
FILTER_VALIDATE_EMAIL μορφή διεύθυνσης email δεν αποδεικνύει ότι υπάρχει το γραμματοκιβώτιο
FILTER_VALIDATE_URL μορφή URL ελέγξτε μόνοι σας το scheme, χωρίς διεθνοποιημένα domains
FILTER_VALIDATE_IP διεύθυνση IP σημαίες για ιδιωτικά και δεσμευμένα εύρη
FILTER_VALIDATE_REGEXP δικό σας μοτίβο αγκυρώστε το μοτίβο με ^ και $

Το φίλτρο καθαρισμού FILTER_SANITIZE_STRING είναι παρωχημένο από την PHP 8.1. Όποιος το χρησιμοποιεί ακόμη, πρέπει να περάσει την επικύρωση σε κατάλληλα φίλτρα και να χρησιμοποιεί το htmlspecialchars() για την έξοδο.

filter_var στην PHP: έλεγχος μιας φόρμας με καθαρό τρόπο

Με το filter_input_array() μια ολόκληρη φόρμα μπορεί να ελεγχθεί σε ένα βήμα απέναντι σε έναν ορισμό. Άγνωστα πεδία δεν γίνονται δεκτά:

<?php
declare(strict_types=1);

$regeln = [
    'menge'   => ['filter' => FILTER_VALIDATE_INT,
                  'options' => ['min_range' => 1, 'max_range' => 50]],
    'email'   => FILTER_VALIDATE_EMAIL,
    'agb'     => ['filter' => FILTER_VALIDATE_BOOL, 'flags' => FILTER_NULL_ON_FAILURE],
    'versand' => ['filter' => FILTER_VALIDATE_REGEXP,
                  'options' => ['regexp' => '/^(standard|express)$/']],
];

$daten  = filter_input_array(INPUT_POST, $regeln) ?? [];
$fehler = [];

foreach ($regeln as $feld => $_) {
    if (!array_key_exists($feld, $daten) || $daten[$feld] === false || $daten[$feld] === null) {
        $fehler[] = $feld;
    }
}

if ($fehler !== []) {
    http_response_code(422);
    // εμφάνιση μηνύματος σφάλματος ανά πεδίο, να μην επεξεργαστεί η είσοδος
}

Προσέξτε τις αυστηρές συγκρίσεις με ===: μια έγκυρη τιμή 0 ή ένα κενό string δεν επιτρέπεται να συγχέεται με αποτυχία. Γιατί οι χαλαρές συγκρίσεις είναι εδώ επικίνδυνες, εξηγεί το Type Juggling: οι χαλαρές συγκρίσεις ως κίνδυνος ασφαλείας. Πώς παρέχει η PHP γενικά τα δεδομένα αιτήματος, περιγράφει το Superglobals: $_GET, $_POST, $_FILES και τα υπόλοιπα.

Παγίδες στα email, στα URL και στα ελεύθερα κείμενα

Ορισμένα φίλτρα κάνουν λιγότερα απ' όσα υποδηλώνει το όνομά τους:

  1. URL: Το FILTER_VALIDATE_URL δέχεται και άλλα schemes εκτός από http και https. Ελέγξτε έπειτα το scheme με το parse_url() απέναντι σε μια σταθερή λίστα. Αν το URL ανακτάται από τον διακομιστή, ισχύουν πρόσθετοι κανόνες, δείτε Αποτροπή του Server-Side Request Forgery στην PHP.
  2. Διευθύνσεις email: Το φίλτρο ελέγχει τη μορφή και όχι την κατοχή. Όποιος χρειάζεται βεβαιότητα, στέλνει έναν σύνδεσμο επιβεβαίωσης.
  3. Ελεύθερο κείμενο: Ονόματα, μηνύματα και διευθύνσεις δύσκολα περιορίζονται λογικά σε συγκεκριμένους χαρακτήρες. Ελέγξτε το μήκος και την κωδικοποίηση χαρακτήρων, για παράδειγμα με το mb_check_encoding($wert, 'UTF-8'), και βασιστείτε κατά την έξοδο στην κωδικοποίηση.
  4. Κανονικές εκφράσεις: Χωρίς ^ και $ ένα μοτίβο ελέγχει μόνο αν εμφανίζεται κάπου στο κείμενο και όχι αν ταιριάζει ολόκληρη η τιμή.
  5. Πίνακες αντί για strings: Ένας επιτιθέμενος μπορεί να στείλει αντί για κείμενο έναν πίνακα. Χωρίς έλεγχο τύπου αυτό οδηγεί σε προειδοποιήσεις ή απρόσμενη συμπεριφορά.
Συμβουλή

Για σταθερές τιμές επιλογής όπως ταξινόμηση, γλώσσα ή τρόπος αποστολής, μια λίστα επιτρεπόμενων με in_array($wert, $erlaubt, true) ή μια έκφραση match είναι απλούστερη και αυστηρότερη από κάθε κανονική έκφραση.

Ένα ακόμη συχνό σφάλμα αφορά αριθμούς με σημασία, όπως τιμές, ποσότητες ή εκπτώσεις. Το ότι μια τιμή είναι έγκυρος αριθμός δεν λέει τίποτα για το αν επιτρέπεται στο πλαίσιό της. Μια αρνητική ποσότητα, μια έκπτωση μεγαλύτερη από την αξία των αγαθών ή μια τιμή που λαμβάνεται από τη φόρμα αντί από τη βάση δεδομένων είναι κλασικά λογικά σφάλματα. Τιμές, δικαιώματα και τιμές κατάστασης ανήκουν γι' αυτό πάντα στον διακομιστή και ποτέ σε κρυφά πεδία φόρμας.

JSON, webhooks και εισαγωγές: επικύρωση πέρα από τις φόρμες

Πολλές είσοδοι σήμερα δεν είναι πια φόρμες, αλλά αιτήματα JSON από εφαρμογές, webhooks από υπηρεσίες πληρωμών ή αρχεία εισαγωγής από προμηθευτές. Και εδώ ισχύει: πρώτα ασφαλής ανάγνωση, μετά έλεγχος. Το OWASP συμβουλεύει να περιορίζονται το μέγεθος και το βάθος εμφώλευσης προτού διαβαστούν τα δεδομένα. Στην PHP το json_decode() με μέγιστο βάθος και JSON_THROW_ON_ERROR αναλαμβάνει ένα μέρος:

<?php
$roh = file_get_contents('php://input', false, null, 0, 65536); // το πολύ 64 KB
try {
    $daten = json_decode($roh, true, 16, JSON_THROW_ON_ERROR);
} catch (JsonException) {
    http_response_code(400);
    exit;
}
if (!is_array($daten) || !is_string($daten['bestellnummer'] ?? null)) {
    http_response_code(422);
    exit;
}

Στα webhooks, πριν από τον έλεγχο του περιεχομένου, τίθεται το ερώτημα αν το μήνυμα προέρχεται πραγματικά από την υπηρεσία που δηλώνεται. Αν η υπηρεσία προσφέρει υπογραφή, την ελέγχετε και τη συγκρίνετε με το hash_equals(). Στα αρχεία εισαγωγής ελέγχετε κάθε γραμμή όπως μια φόρμα και διακόπτετε καθαρά σε περίπτωση σφαλμάτων, αντί να δεχτείτε μισές εγγραφές.

Τα μηνύματα σφάλματος πρέπει να αναφέρουν το επηρεαζόμενο πεδίο, δεν πρέπει όμως να επιστρέφουν αφιλτράριστη την απορριφθείσα τιμή. Αλλιώς δημιουργείται στο ίδιο το μήνυμα σφάλματος ένα νέο σημείο εξόδου, που πρέπει πάλι να κωδικοποιηθεί.

Τι δεν μπορεί να προσφέρει η επικύρωση

Η επικύρωση μικραίνει την επιφάνεια επίθεσης, αλλά κατά το OWASP δεν είναι η κύρια άμυνα απέναντι στο injection. Ένα επώνυμο με απόστροφο είναι έγκυρο και πρέπει παρ' όλα αυτά να φτάσει με ασφάλεια σε μια βάση δεδομένων. Αυτό επιτυγχάνεται μόνο με prepared statements, όπως δείχνει ο οδηγός Αποτροπή του SQL injection στην PHP. Και ένα έγκυρο κείμενο σχολίου γίνεται ακίνδυνο μόνο με κωδικοποίηση ανάλογα με το πλαίσιο κατά την έξοδο.

Η σωστή σειρά είναι λοιπόν: επικύρωση κατά τη λήψη, παραμετροποίηση κατά την επεξεργασία, κωδικοποίηση κατά την έξοδο. Επιπλέον πρέπει να προηγούνται όρια μεγέθους: αιτήματα που είναι υπερβολικά μεγάλα, δεν πρέπει ούτε ο διακομιστής ιστού ούτε η PHP να τα επεξεργάζονται πλήρως. Γι' αυτό χρησιμεύουν ρυθμίσεις όπως το post_max_size, που μετά το PHP2Shell πρέπει ούτως ή άλλως να ελεγχθούν.

Πώς βοηθά συγκεκριμένα η PHP SOS;

  • Καταγράφουμε όλες τις εισόδους της εφαρμογής σας: φόρμες, διεπαφές, uploads, εισαγωγές και webhooks.
  • Καθορίζουμε ανά πεδίο τι επιτρέπεται και αντικαθιστούμε γενικές συναρτήσεις καθαρισμού με σαφείς ελέγχους.
  • Ελέγχουμε αν οι προσβάσεις στη βάση δεδομένων και οι έξοδοι είναι ασφαλισμένες ανεξάρτητα από την επικύρωση.
  • Τεκμηριώνουμε τους κανόνες έτσι ώστε η ομάδα σας να μπορεί να τους συνεχίζει σε νέες λειτουργίες.

Έναν συστηματικό έλεγχο περιγράφει η υπηρεσία Έλεγχος ασφαλείας και δοκιμή διείσδυσης.

Συχνές ερωτήσεις

Ποια είναι η διαφορά ανάμεσα στην επικύρωση και τον καθαρισμό;

Η επικύρωση ελέγχει αν μια τιμή ανταποκρίνεται στις προσδοκίες και αλλιώς την απορρίπτει. Ο καθαρισμός αλλάζει την τιμή, για παράδειγμα αφαιρώντας χαρακτήρες. Για αποφάσεις ασφαλείας η απόρριψη είναι σχεδόν πάντα καλύτερη, επειδή μια τιμή που αλλάζει σιωπηλά μπορεί να δημιουργήσει νέα σφάλματα.

Μπορεί να χρησιμοποιηθεί ακόμη το FILTER_SANITIZE_STRING;

Το φίλτρο έχει χαρακτηριστεί παρωχημένο από την PHP 8.1. Το εγχειρίδιο της PHP συνιστά αντί γι' αυτό το htmlspecialchars() κατά την έξοδο. Ο υπάρχων κώδικας πρέπει να αλλάξει, επειδή οι παρωχημένες συναρτήσεις μπορεί να καταργηθούν σε μελλοντικές εκδόσεις.

Αρκεί το FILTER_VALIDATE_URL για να γίνουν οι σύνδεσμοι ασφαλείς;

Όχι. Το φίλτρο ελέγχει μόνο τη μορφή της διεύθυνσης. Σύμφωνα με το εγχειρίδιο, ένα έγκυρο URL δεν χρειάζεται να αρχίζει με http, γι' αυτό πρέπει να ελέγξετε μόνοι σας το σχήμα (scheme) απέναντι σε λίστα επιτρεπόμενων όπως το https. Τα διεθνοποιημένα ονόματα domain τα απορρίπτει το φίλτρο.

Πρέπει να επικυρώνω και δεδομένα από τη δική μου βάση δεδομένων;

Κατά την έξοδο θεωρούνται μη αξιόπιστα και κωδικοποιούνται κατάλληλα. Μια νέα επικύρωση έχει νόημα όταν τα δεδομένα προέρχονταν αρχικά από έξω και χρησιμοποιούνται τώρα σε νέο πλαίσιο, για παράδειγμα ως όνομα αρχείου ή μέρος μιας εντολής.

Βοηθά η επικύρωση απέναντι στο PHP2Shell;

Όχι. Το PHP2Shell αφορά την επεξεργασία των αιτημάτων στον διερμηνέα PHP, προτού εκτελεστεί καν ο κώδικας της εφαρμογής σας. Απέναντι σε αυτό βοηθά μόνο η ενημέρωση της PHP με επακόλουθη επανεκκίνηση όλων των διεργασιών PHP.

Πηγές

Άμεση επικοινωνία

Κάθε ώρα μετράει. Γράψτε μας τώρα.

Περιγράψτε σύντομα το σύστημα, την έκδοση PHP και ό,τι παρατηρείτε. Θα επικοινωνήσουμε μαζί σας, θα διευκρινίσουμε την κατάσταση και θα εργαστούμε εξ αποστάσεως μέχρι το περιστατικό να κλείσει και να τεκμηριωθεί.

Άμεση βοήθεια