# Αποτροπή του Command Injection στην PHP

> Αποτροπή Command Injection στην PHP: αποφυγή του shell, proc_open με πίνακα, σωστή χρήση του escapeshellarg και εντοπισμός επικίνδυνων κλήσεων στον κώδικα.

Πηγή: https://phpsos.de/el/blog/command-injection-php/  
Ημερομηνία: 25/10/2026  
Πάροχος: PHP SOS, Επείγουσα βοήθεια PHP και ασφάλεια διακομιστών. Άμεση βοήθεια μέσω WhatsApp: https://wa.me/491736494914?text=%CE%93%CE%B5%CE%B9%CE%B1%20%CF%83%CE%B1%CF%82%2C%20PHP%20SOS%2C%20%CF%87%CF%81%CE%B5%CE%B9%CE%B1%CE%B6%CF%8C%CE%BC%CE%B1%CF%83%CF%84%CE%B5%20%CE%B2%CE%BF%CE%AE%CE%B8%CE%B5%CE%B9%CE%B1%20%CE%BC%CE%B5%20%CF%84%CE%BF%CE%BD%20%CE%B4%CE%B9%CE%B1%CE%BA%CE%BF%CE%BC%CE%B9%CF%83%CF%84%CE%AE%20PHP%20%CE%BC%CE%B1%CF%82.%20%CE%95%CF%84%CE%B1%CE%B9%CF%81%CE%B5%CE%AF%CE%B1%3A%20%E2%80%A6%20%CE%99%CF%83%CF%84%CF%8C%CF%84%CE%BF%CF%80%CE%BF%CF%82%3A%20%E2%80%A6

**Εν ολίγοις:** Το Command Injection στην PHP το αποτρέπετε με τον ασφαλέστερο τρόπο αν δεν καλέσετε καθόλου shell: πολλές εργασίες τις αναλαμβάνουν απευθείας συναρτήσεις ή βιβλιοθήκες της PHP. Όπου χρειάζεται εξωτερικό πρόγραμμα, μεταβιβάζετε την εντολή από την PHP 7.4 ως πίνακα στο `proc_open()`, οπότε η PHP εκκινεί το πρόγραμμα χωρίς shell. Τις τιμές τις ελέγχετε απέναντι σε λίστα επιτρεπόμενων, κλείνετε τις επιλογές με `--` και αφήνετε τη διεργασία να εκτελείται με ελάχιστα δικαιώματα.

## Γιατί μια κλήση συστήματος έχει τόση δύναμη

Επεξεργασία εικόνας, δημιουργία PDF, αρχειοθέτηση, σάρωση για ιούς, ερώτημα μιας εγγραφής DNS: για τέτοιες εργασίες οι εφαρμογές PHP καλούν συχνά εξωτερικά προγράμματα. Τεχνικά είναι βολικό, αρκεί μία γραμμή με `exec()` ή `shell_exec()`. Από πλευράς ασφάλειας είναι ένα από τα πιο επικίνδυνα σημεία του κώδικα.

Όταν μια εντολή συναρμολογείται ως κείμενο και εκτελείται από ένα shell, το shell αποφασίζει τι είναι εντολή και τι δεδομένα. Αν μια τιμή απ' έξω εισέλθει αδιάκριτα, μπορεί να αλλάξει το νόημα της εντολής. Το αποτέλεσμα στη χειρότερη περίπτωση είναι το ίδιο με το PHP2Shell: εκτέλεση τυχαίων εντολών στον διακομιστή με τα δικαιώματα της διεργασίας PHP.

Η διαφορά: το PHP2Shell το διορθώνετε με μια ενημέρωση της PHP. Ένα Command Injection στον δικό σας κώδικα παραμένει μετά από κάθε ενημέρωση. Προστίθεται ότι τέτοια σημεία βρίσκονται συχνά σε βοηθητικά σενάρια που προορίζονταν μόνο για διαχειριστές, για παράδειγμα για συντήρηση, διάγνωση ή εισαγωγές, και αργότερα παραμένουν προσβάσιμα χωρίς προστασία.

## Πού δημιουργείται το Command Injection στην PHP

Κινδυνεύει κάθε σημείο όπου η PHP εκκινεί ένα shell ή ένα πρόγραμμα. Οι συναρτήσεις γι' αυτό είναι:

| Συνάρτηση | Χρησιμοποιεί shell; | Υπόδειξη |
|---|---|---|
| `exec()`, `system()`, `passthru()`, `shell_exec()` | ναι | Εντολή ως κείμενο, το shell την ερμηνεύει |
| Τελεστής backtick | ναι | ισοδυναμεί με το `shell_exec()` |
| `popen()` | ναι | Εντολή ως κείμενο |
| `proc_open()` με string | ναι | Εντολή ως κείμενο |
| `proc_open()` με πίνακα | όχι | από την PHP 7.4, τα ορίσματα μεταβιβάζονται απευθείας |
| `mail()` με πέμπτη παράμετρο | έμμεσα | πρόσθετες παράμετροι προς το πρόγραμμα αλληλογραφίας |

Ένα τυπικό ανασφαλές μοτίβο μοιάζει έτσι. Το όνομα αρχείου προέρχεται από το αίτημα και καταλήγει απευθείας στη γραμμή εντολής:

```php
<?php
// ΑΝΑΣΦΑΛΕΣ: μια τιμή από το αίτημα γίνεται μέρος μιας εντολής shell
$datei = $_POST['datei'];
exec('convert uploads/' . $datei . ' -resize 800x800 vorschau/' . $datei);
```

## Πρώτη επιλογή: καθόλου shell

Η πιο αποτελεσματική προστασία είναι να αντικαταστήσετε την κλήση συστήματος. Το OWASP το αναφέρει ρητά ως πρώτη γραμμή άμυνας. Για πολλές εργασίες υπάρχουν στην PHP δικές της συναρτήσεις ή επεκτάσεις:

- Φάκελοι και αρχεία: `mkdir()`, `copy()`, `rename()`, `unlink()`
- Αρχεία: `ZipArchive` ή `PharData`
- Εικόνες: GD ή Imagick ως επέκταση PHP
- Ερωτήματα δικτύου: `dns_get_record()`, `gethostbyname()`, cURL
- Αθροίσματα ελέγχου: `hash_file()`

Έτσι εξαφανίζεται εντελώς το ερώτημα ποιοι χαρακτήρες ερμηνεύονται από ένα shell. Επιπλέον, οι συναρτήσεις για εντολές συστήματος μπορούν τότε να κλειδωθούν στη διαμόρφωση, όπως περιγράφει ο οδηγός [Σωστή χρήση του disable_functions](https://phpsos.de/el/ratgeber/disable-functions/).

## Όταν χρειάζεται εξωτερικό πρόγραμμα: proc_open με πίνακα

Από την PHP 7.4 το `proc_open()` δέχεται την εντολή ως πίνακα. Σύμφωνα με το εγχειρίδιο της PHP, η διεργασία εκκινείται τότε απευθείας, χωρίς παράκαμψη μέσω του shell, και η PHP αναλαμβάνει την απαραίτητη προστασία (escaping) των ορισμάτων. Χαρακτήρες όπως η άνω τελεία ή το pipe δεν έχουν πια ειδική σημασία.

```php
<?php
declare(strict_types=1);

$name = basename((string) ($_POST['datei'] ?? ''));
if (!preg_match('/^[a-z0-9_-]{1,64}\.(jpg|png)$/', $name)) {
    throw new InvalidArgumentException('Ungültiger Dateiname.');
}

$befehl = ['/usr/bin/convert', '/srv/app/uploads/' . $name, '-resize', '800x800',
           '/srv/app/vorschau/' . $name];

$prozess = proc_open($befehl, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes);
if (!is_resource($prozess)) {
    throw new RuntimeException('Programm konnte nicht gestartet werden.');
}
$fehlerausgabe = stream_get_contents($pipes[2]);
$status = proc_close($prozess);
```

Τρία πράγματα κάνουν το παράδειγμα στιβαρό: το πρόγραμμα ορίζεται στον κώδικα με πλήρη διαδρομή, το όνομα αρχείου ελέγχεται απέναντι σε ένα στενό μοτίβο και κάθε μεταβλητό όρισμα αρχίζει με απόλυτη διαδρομή, άρα δεν μπορεί να διαβαστεί ως επιλογή. Όπου μια τιμή βρίσκεται μόνη της, κλείνετε τις επιλογές με `--`, εφόσον το πρόγραμμα το υποστηρίζει σύμφωνα με την τεκμηρίωσή του, ή απορρίπτετε τιμές που αρχίζουν με παύλα.

Για εργασίες που χρειάζονται τακτικά εξωτερικά προγράμματα, για παράδειγμα επεξεργασία εικόνων ή PDF σε μεγαλύτερη κλίμακα, αξίζει ένας διαχωρισμός: η εφαρμογή ιστού καταχωρεί μόνο μια εργασία σε μια ουρά και μια ξεχωριστή υπηρεσία παρασκηνίου με δικό της χρήστη και δικά της δικαιώματα την εκτελεί. Η διεργασία PHP που απαντά σε αιτήματα από το διαδίκτυο δεν χρειάζεται τότε πια συναρτήσεις για εντολές συστήματος και μπορούν να κλειδωθούν γι' αυτήν. Τα εξωτερικά προγράμματα πρέπει επιπλέον να έχουν όρια χρόνου και μνήμης, ώστε μια μεμονωμένη εργασία να μην μπλοκάρει τον διακομιστή.

Μια ειδική περίπτωση είναι το `mail()`. Η πέμπτη παράμετρος μεταβιβάζει πρόσθετες επιλογές στο πρόγραμμα αλληλογραφίας του συστήματος. Τιμές από φόρμες, για παράδειγμα μια διεύθυνση αποστολέα, δεν επιτρέπεται ποτέ να φτάνουν εκεί αδιάκριτα. Πιο στιβαρή είναι μια βιβλιοθήκη αλληλογραφίας που στέλνει μέσω SMTP και δεν χρειάζεται κλήση συστήματος.

## escapeshellarg: σωστή χρήση και γνώση των ορίων

Όπου ο υπάρχων κώδικας εργάζεται ακόμη με γραμμές εντολών, το `escapeshellarg()` για κάθε μεμονωμένη τιμή είναι το ελάχιστο μέτρο. Η συνάρτηση βάζει την τιμή σε εισαγωγικά, ώστε το shell να την αντιμετωπίζει ως ακριβώς ένα όρισμα. Το `escapeshellcmd()` είναι ακατάλληλο για είσοδο χρήστη, επειδή επιτρέπει πρόσθετες παραμέτρους, όπως δείχνει το OWASP με ένα παράδειγμα.

Σημαντικά όρια του `escapeshellarg()`:

1. **Το Argument Injection παραμένει δυνατό:** Μια τιμή με escape που αρχίζει με παύλα διαβάζεται παρ' όλα αυτά από το πρόγραμμα-στόχο ως επιλογή.
2. **Τα Windows συμπεριφέρονται διαφορετικά:** Εκεί η συνάρτηση αντικαθιστά σύμφωνα με το εγχειρίδιο ορισμένους χαρακτήρες όπως τα `%` και `"` με κενά· οι τιμές φτάνουν δηλαδή αλλοιωμένες.
3. **Σύνολο χαρακτήρων:** Ανάλογα με τη ρύθμιση locale του διακομιστή, χαρακτήρες εκτός ASCII μπορεί να χαθούν.

## Εντοπισμός των σημείων στον υπάρχοντα κώδικα

Μια αναζήτηση κλήσεων συστήματος γίνεται γρήγορα και δίνει μια διαχειρίσιμη λίστα:

```bash
grep -rnE "\b(exec|system|passthru|shell_exec|popen|proc_open)\s*\(" src/ --include="*.php"
grep -rn '`' src/ --include="*.php" | grep -v '^\s*//'
```

Κάθε εύρημα χρειάζεται απάντηση σε τρία ερωτήματα: Μπορεί να αντικατασταθεί η κλήση από συναρτήσεις PHP; Εισρέουν τιμές απ' έξω; Με ποια δικαιώματα εκτελείται η διεργασία; Το τελευταίο ερώτημα είναι αποφασιστικό για τη ζημιά στη χειρότερη περίπτωση. Μια διεργασία PHP με δικό της χρήστη και χωρίς δικαιώματα εγγραφής στον κώδικα προκαλεί λιγότερη ζημιά, δείτε [Least Privilege: τα δικαιώματα του χρήστη του διακομιστή ιστού](https://phpsos.de/el/blog/rechte-des-webserver-benutzers/).

> **Σημαντικό:**
> Αν μια διεργασία PHP-FPM ή διακομιστή ιστού εκκινεί ένα shell, αυτό είναι ισχυρή ένδειξη εισβολής. Πώς το αναγνωρίζετε, περιγράφει το [Προειδοποιητικό σημάδι: ο διακομιστής ιστού εκκινεί shell](https://phpsos.de/el/blog/webserver-startet-shell/).

## Πώς βοηθά συγκεκριμένα η PHP SOS;

- Αναζητούμε όλες τις κλήσεις συστήματος στην εφαρμογή σας, στα πρόσθετα και στα βοηθητικά σενάρια.
- Αντικαθιστούμε τις κλήσεις, όπου είναι δυνατό, με συναρτήσεις PHP και μετατρέπουμε τις υπόλοιπες σε κλήσεις χωρίς shell.
- Κλειδώνουμε στη διαμόρφωση της PHP τις συναρτήσεις που δεν χρειάζονται και ελέγχουμε τα δικαιώματα του χρήστη PHP.
- Δοκιμάζουμε τις αλλαγές και τεκμηριώνουμε ποια προγράμματα επιτρέπεται ακόμη να καλεί η εφαρμογή.

Τον έλεγχο του δικού σας λογισμικού προσφέρουμε ως [έλεγχο ασφαλείας και δοκιμή διείσδυσης](https://phpsos.de/el/leistungen/sicherheitsaudit-penetrationstest/).


## Συχνές ερωτήσεις

**Αρκεί το escapeshellarg απέναντι στο Command Injection;**  
Εμποδίζει μια τιμή να εκτελεστεί ως επιπλέον εντολή. Δεν εμποδίζει την τιμή να διαβαστεί ως επιλογή του προγράμματος που καλείται, αν αρχίζει με παύλα. Γι' αυτό ελέγχετε επιπλέον τις τιμές και, όπου το πρόγραμμα το υποστηρίζει, κλείνετε τις επιλογές με --.

**Ποια είναι η διαφορά ανάμεσα στο escapeshellarg και το escapeshellcmd;**  
Το escapeshellarg χειρίζεται μια μεμονωμένη τιμή ως ακριβώς ένα όρισμα. Το escapeshellcmd κάνει escape μόνο σε μετα-χαρακτήρες μέσα σε ολόκληρη γραμμή εντολής και επιτρέπει πρόσθετες παραμέτρους. Για είσοδο χρήστη το escapeshellarg είναι η σωστή επιλογή, μια κλήση χωρίς shell είναι ακόμη καλύτερη.

**Πρέπει να αποκλείσω τα exec και system μέσω disable_functions;**  
Αν η εφαρμογή σας δεν τα χρειάζεται, ναι. Αυτό περιορίζει τη ζημιά μετά από μια εισβολή. Δεν αντικαθιστά όμως τον ασφαλή κώδικα, γιατί οι εφαρμογές που χρειάζονται εντολές εξακολουθούν να χρειάζονται τις συναρτήσεις.

**Πώς καταλαβαίνω αν έχει γίνει εκμετάλλευση ενός Command Injection;**  
Ισχυρή προειδοποίηση είναι οι διεργασίες PHP ή διακομιστή ιστού που εκκινούν ένα shell όπως το sh ή το bash. Προστίθενται άγνωστες διεργασίες, νέα αρχεία σε φακέλους upload και ασυνήθιστες εξερχόμενες συνδέσεις.

## Πηγές

- [OWASP OS Command Injection Defense Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html)
- [Εγχειρίδιο της PHP: proc_open](https://www.php.net/manual/de/function.proc-open.php)
- [Εγχειρίδιο της PHP: escapeshellarg](https://www.php.net/manual/de/function.escapeshellarg.php)
