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

Ασφαλή uploads αρχείων στην PHP: ασφάλεια upload

Οι φόρμες upload είναι συχνός δρόμος για webshells. Πώς ελέγχετε σωστά τους τύπους αρχείων, αποθηκεύετε ασφαλώς τα αρχεία και αποτρέπετε τον διακομιστή από το να εκτελεί scripts που ανέβηκαν.

Ημερομηνία 6 λεπτά ανάγνωσηςΟδηγοί

Εν συντομία: Στην ασφάλεια upload της PHP δεν αποφασίζει ένας μεμονωμένος έλεγχος, αλλά ο συνδυασμός: έλεγχος του τύπου αρχείου στον διακομιστή, μετονομασία των αρχείων, αποθήκευση εκτός webroot και καμία εκτέλεση scripts στον φάκελο upload. Μια φόρμα upload χωρίς έλεγχο είναι ένας από τους κλασικούς τρόπους με τους οποίους οι επιτιθέμενοι φέρνουν μια κερκόπορτα σε έναν διακομιστή ιστού.

Γιατί οι φόρμες upload είναι προνομιακή είσοδος

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

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

Για διαχειριστές και προγραμματιστές αυτό σημαίνει: ο κώδικας της εφαρμογής και η διαμόρφωση του διακομιστή πρέπει να ταιριάζουν. Μια αδυναμία σε ένα επίπεδο αναχαιτίζεται συχνά από το άλλο, όταν και τα δύο έχουν υλοποιηθεί σωστά. Πώς θα βρείτε αρχεία που έχουν ήδη εισαχθεί κρυφά, περιγράφει ο οδηγός Εντοπισμός και αφαίρεση webshell.

Οι βασικοί κανόνες για την ασφάλεια upload στην PHP

Οι παρακάτω κανόνες αντιστοιχούν στις συστάσεις των OWASP Cheat Sheets και έχουν αποδειχθεί στη λειτουργία:

  • Λίστα επιτρεπόμενων αντί για λίστα αποκλεισμένων: Δεχτείτε μόνο ρητά επιτρεπόμενους τύπους αρχείων, για παράδειγμα PDF, JPG και PNG. Οι λίστες αποκλεισμού για μεμονωμένες καταλήξεις παρακάμπτονται μέσω παραλλαγών και διπλών καταλήξεων.
  • Ελέγξτε το περιεχόμενο, όχι μόνο την κατάληξη: Προσδιορίστε τον πραγματικό τύπο στον διακομιστή με το finfo. Ο τύπος MIME στο $_FILES είναι στοιχείο του αποστολέα και δεν είναι αξιόπιστος.
  • Νέο όνομα αρχείου: Μη χρησιμοποιείτε ποτέ το αρχικό όνομα ως όνομα αρχείου. Δημιουργήστε ένα τυχαίο όνομα και προσθέστε την κατάληξη από τη λίστα επιτρεπόμενων.
  • Αποθήκευση εκτός webroot: Αποθηκεύστε τα αρχεία ώστε να μην είναι προσβάσιμα άμεσα μέσω URL. Η παράδοση γίνεται μέσω ενός script με έλεγχο δικαιωμάτων.
  • Περιορισμός μεγέθους: Στην εφαρμογή, στην PHP και στον διακομιστή ιστού.
  • Καμία εκτέλεση: Αν τα uploads πρέπει παρ' όλα αυτά να βρίσκονται στο webroot, απενεργοποιήστε την εκτέλεση scripts σε αυτόν τον κατάλογο.
  • Έλεγχος μόνο στον διακομιστή: Οι έλεγχοι JavaScript στο πρόγραμμα περιήγησης βελτιώνουν τη χρήση, δεν προστατεύουν όμως.

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

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

<?php
declare(strict_types=1);

const MAX_BYTES  = 5 * 1024 * 1024; // 5 MB
const ERLAUBT    = [
    'application/pdf' => 'pdf',
    'image/jpeg'      => 'jpg',
    'image/png'       => 'png',
];
const ZIELORDNER = '/var/www/daten/uploads'; // εκτός του webroot

$datei = $_FILES['dokument'] ?? null;

if (!is_array($datei) || $datei['error'] !== UPLOAD_ERR_OK) {
    http_response_code(400);
    exit('Upload fehlgeschlagen.');
}

if ($datei['size'] > MAX_BYTES || !is_uploaded_file($datei['tmp_name'])) {
    http_response_code(400);
    exit('Datei ungültig.');
}

$finfo = new finfo(FILEINFO_MIME_TYPE);
$typ   = $finfo->file($datei['tmp_name']);

if (!isset(ERLAUBT[$typ])) {
    http_response_code(415);
    exit('Dateityp nicht erlaubt.');
}

$name = bin2hex(random_bytes(16)) . '.' . ERLAUBT[$typ];
$ziel = ZIELORDNER . '/' . $name;

if (!move_uploaded_file($datei['tmp_name'], $ziel)) {
    http_response_code(500);
    exit('Speichern fehlgeschlagen.');
}

chmod($ziel, 0640);
// Αποθηκεύστε το αρχικό όνομα μόνο ως κείμενο στη βάση δεδομένων
// και κάντε escape με htmlspecialchars() σε κάθε εμφάνισή του.

Στις εικόνες αξίζει ένα επιπλέον βήμα: κωδικοποιήστε ξανά την εικόνα με GD ή Imagick, απορρίπτοντας τα μεταδεδομένα. Αυτό δεν αντικαθιστά τους άλλους ελέγχους, μειώνει όμως τον υπολειπόμενο κίνδυνο από ενσωματωμένα ξένα δεδομένα.

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

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

Συμβουλή

Παραδώστε τα αρχεία από τον προστατευμένο φάκελο με Content-Disposition: attachment και X-Content-Type-Options: nosniff. Τότε το πρόγραμμα περιήγησης δεν εμφανίζει άμεσα προβληματικά περιεχόμενα, αλλά τα προσφέρει ως λήψη.

Απενεργοποίηση της εκτέλεσης PHP στον φάκελο upload

Ακόμη και αν ένα αρχείο με λάθος περιεχόμενο διαφύγει, ο διακομιστής ιστού δεν επιτρέπεται να το εκτελέσει ως script. Αυτό το δεύτερο προστατευτικό επίπεδο ανήκει σε κάθε διακομιστή που αποθηκεύει uploads στο webroot.

Για Nginx με PHP-FPM:

location ^~ /uploads/ {
    location ~* \.(php|phtml|phar)$ {
        deny all;
    }
}

Για Apache, κατά προτίμηση απευθείας στο VirtualHost αντί σε ένα .htaccess, ώστε ο κανόνας να μην μπορεί να αντικατασταθεί από την εφαρμογή:

<Directory "/var/www/html/uploads">
    AllowOverride None
    <FilesMatch "\.(php|phtml|phar)$">
        Require all denied
    </FilesMatch>
</Directory>

Αν η PHP εκτελείται ως module του Apache (mod_php), μπορείτε στο ίδιο μπλοκ να ορίσετε επιπλέον php_admin_flag engine off. Μετά την αλλαγή ελέγξτε με ένα αβλαβές αρχείο δοκιμής, που εμφανίζει μόνο ένα κείμενο, ότι ο διακομιστής απαντά σε ένα αίτημα προς αυτό με 403.

Όρια μεγέθους και η σχέση με το PHP2Shell

Τα uploads σχετίζονται στενά με τις ρυθμίσεις PHP post_max_size και upload_max_filesize. Στο πλαίσιο του PHP2Shell το php.net συνιστά ως προσωρινό μέτρο να οριστεί το post_max_size σε 8M, όταν δεν χρειάζονται uploads, ή σε 32M με uploads, και το upload_max_filesize να διατηρηθεί χαμηλότερα. Αυτό δεν αποτελεί πλήρη προστασία και δεν αντικαθιστά την ενημέρωση σε διορθωμένη έκδοση PHP.

; php.ini ή pool FPM (php_admin_value), στη συνέχεια επανεκκίνηση όλων των workers
file_uploads        = On
post_max_size       = 32M
upload_max_filesize = 20M
max_file_uploads    = 5

Αν ένας ιστότοπος δεν χρειάζεται καθόλου uploads, η πιο καθαρή λύση είναι file_uploads = Off. Ποιες ρυθμίσεις έχουν νόημα μέχρι το patch, αναφέρεται στη σελίδα Άμεσα μέτρα χωρίς patch. Κατάλληλα δικαιώματα για καταλόγους upload περιγράφει ο οδηγός Δικαιώματα αρχείων στον διακομιστή ιστού.

Τυπικά λάθη στις λειτουργίες upload

Στον έλεγχο υπαρχουσών εφαρμογών εμφανίζονται ξανά και ξανά τα ίδια μοτίβα. Ελέγξτε τις φόρμες σας στοχευμένα για αυτά τα σημεία:

  • Η κατάληξη ελέγχεται μόνο εν μέρει, με αποτέλεσμα να περνούν ονόματα αρχείων με πολλαπλές καταλήξεις.
  • Το αρχικό όνομα από τη φόρμα καταλήγει στη διαδρομή αποθήκευσης. Αυτό ανοίγει δρόμους για χειραγώγηση διαδρομών και αντικατάσταση υπαρχόντων αρχείων.
  • Τα uploads βρίσκονται δημόσια με προβλέψιμα ονόματα. Σε αιτήσεις εργασίας ή συμβόλαια αυτό αποτελεί και πρόβλημα προστασίας δεδομένων.
  • Ο φάκελος upload είναι εγγράψιμος από τον διακομιστή ιστού και ταυτόχρονα εκτελέσιμος.
  • Παλιές επεκτάσεις upload ή plugins φορμών δεν ενημερώνονται, παρόλο που ο κατασκευαστής έχει δημοσιεύσει ενημερώσεις ασφαλείας.
  • Τα σφάλματα δεν καταγράφονται. Τα απορριφθέντα uploads είναι όμως ένα πρώιμο σήμα στοχευμένων προσπαθειών.

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

  • Ελέγχουμε τις λειτουργίες upload στον κώδικα και στη διαμόρφωση του διακομιστή και κατονομάζουμε συγκεκριμένες αδυναμίες με προτεραιότητα.
  • Εφαρμόζουμε τον αποκλεισμό εκτέλεσης στον φάκελο upload, κατάλληλα δικαιώματα και όρια μεγέθους στο πλαίσιο της θωράκισης διακομιστή.
  • Σε περίπτωση υποψίας, αναζητούμε στους καταλόγους upload scripts που έχουν εισαχθεί κρυφά και τους καθαρίζουμε μέσω της αφαίρεσης κακόβουλου λογισμικού.
  • Κατόπιν αιτήματος αφήνουμε την υλοποίηση να επαληθευτεί ανεξάρτητα από ένα penetration test.

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

Αρκεί να ελέγχω την κατάληξη του αρχείου κατά το upload;

Όχι. Η κατάληξη και ο τύπος MIME που αναφέρει το πρόγραμμα περιήγησης προέρχονται από τον αποστολέα και μπορούν να επιλεγούν ελεύθερα. Ελέγξτε το περιεχόμενο στον διακομιστή, δώστε νέο όνομα αρχείου και αποκλείστε την εκτέλεση scripts στον κατάλογο upload.

Πού πρέπει να αποθηκεύονται τα αρχεία που ανεβαίνουν;

Κατά προτίμηση εκτός του δημόσιου καταλόγου ιστού. Την παράδοση αναλαμβάνει τότε ένα script που ελέγχει προηγουμένως αν ο χρήστης επιτρέπεται να δει το αρχείο. Έτσι τα αρχεία δεν είναι ούτε άμεσα προσβάσιμα ούτε εκτελέσιμα.

Είναι τα αρχεία SVG ως εικόνες αβλαβή;

Όχι αυτόματα. Το SVG είναι XML και μπορεί να περιέχει ενεργό περιεχόμενο. Επιτρέψτε το SVG μόνο αν καθαρίζετε τα αρχεία ή αν τα παραδίδετε αποκλειστικά ως λήψη με κατάλληλη κεφαλίδα Content-Disposition.

Έχει το μέγεθος του upload σχέση με το PHP2Shell;

Ναι, έμμεσα. Το php.net συνιστά ως προσωρινό μέτρο χαμηλότερες τιμές για τα post_max_size και upload_max_filesize. Αυτό μειώνει τον κίνδυνο, δεν αντικαθιστά όμως την ενημέρωση σε διορθωμένη έκδοση PHP και την επανεκκίνηση όλων των workers.

Πηγές

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

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

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

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