# Type Juggling στην PHP: οι χαλαρές συγκρίσεις ως κίνδυνος ασφαλείας

> Κατανοήστε το PHP Type Juggling: πώς συγκρίνει το ==, τι άλλαξε στην PHP 8.0 και γιατί tokens, hashes και ρόλοι πρέπει να συγκρίνονται αυστηρά.

Πηγή: https://phpsos.de/el/blog/type-juggling-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

**Εν ολίγοις:** Με Type Juggling στην PHP εννοούμε την αυτόματη μετατροπή τύπων, που στη χαλαρή σύγκριση με `==` καθορίζει το αποτέλεσμα. Από την PHP 8.0 οι κανόνες είναι αυστηρότεροι, τα αριθμητικά strings όμως συνεχίζουν να συγκρίνονται ως αριθμοί και τα `true`, `false` και `null` ακολουθούν δικούς τους κανόνες. Για ελέγχους σχετικούς με την ασφάλεια ισχύει γι' αυτό: `===`, `in_array(..., true)`, `match` αντί για `switch`, `hash_equals()` για tokens και `password_verify()` για κωδικούς.

## Μια σύγκριση που είναι αληθής, παρότι δεν θα έπρεπε

Πολλές ευπάθειες σε εφαρμογές PHP δεν κρύβονται σε περίπλοκες συναρτήσεις, αλλά σε έναν μόνο χαρακτήρα: ένα `==` εκεί που έπρεπε να υπάρχει `===`. Ο κώδικας δείχνει σωστός, οι δοκιμές με κανονικές εισόδους περνούν, και παρ' όλα αυτά ο έλεγχος αφήνει κάτω από ορισμένες συνθήκες να περάσει κάτι που έπρεπε να σταματήσει.

Η αιτία είναι ένα χαρακτηριστικό της PHP που στην καθημερινότητα είναι πρακτικό: οι τιμές μετατρέπονται όταν χρειάζεται σε άλλον τύπο. Ένα string από μια φόρμα μπορεί έτσι να συγκριθεί χωρίς παρακάμψεις με έναν αριθμό από τη βάση δεδομένων. Σε συνδέσεις, tokens, ρόλους ή πεδία κατάστασης αυτή ακριβώς η γενναιοδωρία μπορεί να γίνει επικίνδυνη.

## Πώς συγκρίνει η PHP με το ==

Το εγχειρίδιο της PHP περιγράφει αναλυτικά τους κανόνες για τις χαλαρές συγκρίσεις. Για την ασφάλεια σημαντικές είναι κυρίως αυτές οι περιπτώσεις:

| Σύγκριση | PHP 7 | PHP 8 | Λόγος |
|---|---|---|---|
| `0 == "a"` | αληθές | ψευδές | από την PHP 8.0 συγκρίνονται ως strings |
| `"1" == "01"` | αληθές | αληθές | και τα δύο αριθμητικά, σύγκριση ως αριθμός |
| `"10" == "1e1"` | αληθές | αληθές | η εκθετική γραφή είναι αριθμητική |
| `100 == "1e2"` | αληθές | αληθές | αριθμός απέναντι σε αριθμητικό string |
| `null == false` | αληθές | αληθές | σύγκριση ως λογική τιμή |
| `"abc" == true` | αληθές | αληθές | ένα μη κενό string θεωρείται αληθές |

Η αλλαγή στην PHP 8.0 εξουδετέρωσε μια ολόκληρη κατηγορία σφαλμάτων: παλαιότερα ένα μη αριθμητικό string γινόταν `0` στη σύγκριση με έναν αριθμό. Αυτό αφορούσε και τις εντολές `switch`. Οι υπόλοιπες γραμμές του πίνακα δείχνουν όμως ότι οι χαλαρές συγκρίσεις κρύβουν ακόμη εκπλήξεις.

Και οι τελεστές `<`, `>` και ο τελεστής σύγκρισης `<=>` ακολουθούν αυτούς τους κανόνες. Στις ταξινομήσεις αυτό είναι συνήθως ακίνδυνο, σε ελέγχους όπως «ποσό μικρότερο από το όριο» με τιμές από το αίτημα, ο τύπος πρέπει να έχει καθοριστεί εκ των προτέρων.

Ιδιαίτερα ύπουλη είναι η γραμμή με την εκθετική γραφή. Οι τιμές hash και τα tokens αποτελούνται συχνά από ψηφία και γράμματα. Αν μια τέτοια τιμή μοιάζει τυχαία με αριθμό σε εκθετική γραφή, το `==` συγκρίνει δύο διαφορετικά hashes ενδεχομένως ως ίσα. Αυτό είναι το υπόβαθρο πολλών αναφορών για παράκαμψη συνδέσεων σε παλαιότερες εφαρμογές PHP.

## PHP Type Juggling σε τυπικούς ελέγχους ασφαλείας

Οι χαλαρές συγκρίσεις κρύβονται σε περισσότερα σημεία από τον τελεστή `==`:

1. **Οι `in_array()` και `array_search()`** συγκρίνουν χωρίς τρίτη παράμετρο χαλαρά. Μια λίστα επιτρεπόμενων με ρόλους ή ταυτότητες γίνεται έτσι πιο χαλαρή απ' όσο νομίζετε.
2. **Το `switch`** συγκρίνει χαλαρά. Η έκφραση `match`, διαθέσιμη από την PHP 8.0, συγκρίνει αντίθετα σύμφωνα με το εγχειρίδιο με ασφάλεια τύπων μέσω `===` και πετά σφάλμα αν δεν ταιριάζει κανένας κλάδος.
3. **Οι είσοδοι JSON** επιστρέφουν πραγματικούς τύπους. Ένα πεδίο που περιμένετε ως string μπορεί να φτάσει ως `true` ή ως αριθμός και να ταιριάξει απρόσμενα με το `==`.
4. **Το `strcmp()` για μυστικά** είναι ακατάλληλο, επειδή ο χρόνος εκτέλεσης εξαρτάται από το περιεχόμενο και οι περιπτώσεις σφάλματος αξιολογούνται εύκολα λανθασμένα.
5. **Έλεγχος τιμών επιστροφής**: Συναρτήσεις όπως η `strpos()` επιστρέφουν `0` για εύρημα στην αρχή και `false` για κανένα εύρημα. Το `if (!strpos(...))` συγχέει τα δύο.

## Ασφαλείς συγκρίσεις: η αντιπαραβολή

Τα παρακάτω παραδείγματα δείχνουν κάθε φορά την ανασφαλή και την ασφαλή παραλλαγή:

```php
<?php
declare(strict_types=1);

// έλεγχος ρόλου
$erlaubteRollen = ['admin', 'redaktion'];
in_array($rolle, $erlaubteRollen);          // ανασφαλές: χαλαρή
in_array($rolle, $erlaubteRollen, true);    // ασφαλές: αυστηρή

// αξιολόγηση κατάστασης
$aktion = match ($status) {                 // αυστηρό, σφάλμα για άγνωστη τιμή
    'offen'      => 'bearbeiten',
    'erledigt'   => 'archivieren',
};

// έλεγχος token από σύνδεσμο
if ($tokenAusLink == $gespeichertesToken) { /* μη ασφαλές */ }
if (is_string($tokenAusLink) && hash_equals($gespeichertesToken, $tokenAusLink)) { /* ασφαλές */ }

// έλεγχος κωδικού
if (md5($eingabe) == $hash) { /* μη ασφαλές: αδύναμος αλγόριθμος και χαλαρή σύγκριση */ }
if (password_verify($eingabe, $hash)) { /* ασφαλές */ }

// αναζήτηση υποσυμβολοσειράς
if (strpos($text, 'abc') !== false) { /* korrekt: auch Treffer an Position 0 */ }
```

Το `hash_equals()` περιμένει σύμφωνα με το εγχειρίδιο ως πρώτη παράμετρο το γνωστό μυστικό και ως δεύτερη την τιμή του χρήστη και συγκρίνει σε σταθερό χρόνο. Πώς δημιουργείτε εν γένει tokens με ασφάλεια, περιγράφει το [Ασφαλείς τυχαίοι αριθμοί και tokens στην PHP](https://phpsos.de/el/blog/sichere-tokens-php/).

> **Σημαντικό:**
> Το `declare(strict_types=1)` δεν κάνει τις συγκρίσεις αυστηρές. Η εντολή αφορά μόνο τη μετατροπή τύπων σε κλήσεις συναρτήσεων και τιμές επιστροφής. Τις χαλαρές συγκρίσεις πρέπει να τις αντικαταστήσετε εσείς στον κώδικα.

Οι αυστηρές συγκρίσεις έχουν και μια αρνητική πλευρά: αποτυγχάνουν όταν οι τύποι δεν ταιριάζουν. Το `'42' === 42` είναι ψευδές. Οι τιμές από φόρμες και URL φτάνουν στην PHP ως strings, οι τιμές από τη βάση δεδομένων ανάλογα με τον οδηγό και τη ρύθμιση ως strings ή αριθμοί. Όποιος εισάγει παντού `===` χωρίς να εξισώσει τους τύπους, δημιουργεί σφάλματα που στη λειτουργία γίνονται αντιληπτά ως απόρριψη νόμιμων χρηστών.

Η λύση είναι ένα σαφές όριο: οι είσοδοι επικυρώνονται κατά τη λήψη και μετατρέπονται στον σωστό τύπο, για παράδειγμα με `filter_var($wert, FILTER_VALIDATE_INT)`, και στη συνέχεια στον κώδικα αντιμετωπίζονται μόνο με δηλώσεις τύπων και αυστηρές συγκρίσεις. Οι δηλώσεις τύπων σε παραμέτρους, τιμές επιστροφής και ιδιότητες βοηθούν, επειδή οι λανθασμένοι τύποι γίνονται τότε νωρίς αντιληπτοί με ένα μήνυμα σφάλματος, αντί να χάνονται σιωπηλά μέσα σε μια σύγκριση.

## Συστηματικός έλεγχος του υπάρχοντος κώδικα

Σε έργα που έχουν μεγαλώσει με τον καιρό, οι χαλαρές συγκρίσεις βρίσκονται κατά εκατοντάδες. Δεν είναι κάθε μία πρόβλημα. Συγκεντρωθείτε σε σημεία όπου παίρνεται απόφαση για πρόσβαση:

```bash
# Χαλαρές συγκρίσεις σε γραμμές με όρους σχετικούς με την ασφάλεια
grep -rnE "[^=!]==[^=]" src/ --include="*.php" | grep -iE "token|hash|pass|role|rolle|admin|auth|sign"
# in_array χωρίς αυστηρή σύγκριση
grep -rnE "in_array\([^)]*\)" src/ --include="*.php" | grep -v ", true)"
```

Εργαλεία στατικής ανάλυσης όπως το PHPStan ή το Psalm μπορούν, αν το επιθυμείτε, να αναφέρουν μόνιμα τις χαλαρές συγκρίσεις. Έτσι οι νέες περιπτώσεις δεν φτάνουν καν στον κύριο κλάδο. Τα βασικά για τους τύπους περιγράφει το [Το σύστημα τύπων της PHP](https://phpsos.de/el/php/typsystem/)· πώς φέρνετε νωρίτερα τις εισόδους στον σωστό τύπο, δείχνει το [Επικύρωση και φιλτράρισμα εισόδου στην PHP](https://phpsos.de/el/blog/eingaben-validieren-php/).

## Τι σημαίνει αυτό για τα παλαιά συστήματα

Εφαρμογές που εκτελούνται ακόμη σε PHP 7 επηρεάζονται από τους παλιούς, πιο χαλαρούς κανόνες σύγκρισης. Προστίθεται ένα δεύτερο πρόβλημα: για την PHP 8.1 και παλαιότερες δεν υπάρχουν πια επίσημες ενημερώσεις ασφαλείας από το έργο PHP, ούτε απέναντι στο PHP2Shell. Την κατάσταση περιγράφει το [PHP 8.1 και παλαιότερες: τι ισχύει τώρα](https://phpsos.de/el/php2shell/php-8-1-und-aelter/).

Σε μια μετάβαση στην PHP 8 αλλάζουν ορισμένα αποτελέσματα συγκρίσεων. Αυτό είναι συνήθως βελτίωση, μπορεί όμως να χαλάσει κώδικα που βασιζόταν στην παλιά συμπεριφορά. Προγραμματίστε γι' αυτό δοκιμές που καλύπτουν στοχευμένα συγκρίσεις με αριθμούς, κενές τιμές και `null`.

## Πώς βοηθά συγκεκριμένα η PHP SOS;

- Ψάχνουμε τον κώδικά σας για χαλαρές συγκρίσεις σε σημεία που αποφασίζουν για σύνδεση, δικαιώματα ή πληρωμές.
- Τις αντικαθιστούμε με αυστηρές συγκρίσεις, εκφράσεις `match` και κατάλληλες συναρτήσεις ελέγχου.
- Ρυθμίζουμε τη στατική ανάλυση έτσι ώστε οι νέες χαλαρές συγκρίσεις να γίνονται αντιληπτές στο build.
- Συνοδεύουμε μεταβάσεις σε τρέχουσες εκδόσεις PHP με δοκιμές για τους αλλαγμένους κανόνες σύγκρισης.

Έναν έλεγχο του λογισμικού σας περιγράφει ο [Έλεγχος ασφαλείας και δοκιμή διείσδυσης](https://phpsos.de/el/leistungen/sicherheitsaudit-penetrationstest/).


## Συχνές ερωτήσεις

**Τι είναι το Type Juggling στην PHP;**  
Η PHP μετατρέπει αυτόματα τιμές διαφορετικών τύπων σε ορισμένες πράξεις, για παράδειγμα ένα string σε αριθμό. Στη χαλαρή σύγκριση με == αυτή η μετατροπή καθορίζει το αποτέλεσμα. Αυτό είναι βολικό, μπορεί όμως να οδηγήσει σε συγκρίσεις που είναι αληθείς, παρότι οι τιμές δεν μοιάζουν ίδιες.

**Έλυσε η PHP 8 το πρόβλημα;**  
Εν μέρει. Από την PHP 8.0 ένας αριθμός συγκρίνεται με ένα μη αριθμητικό string ως string, άρα το 0 == 'a' δεν είναι πια αληθές. Δύο αριθμητικά strings εξακολουθούν όμως να συγκρίνονται ως αριθμοί, και οι συγκρίσεις με true, false και null ακολουθούν δικούς τους κανόνες.

**Βοηθά το declare(strict_types=1) απέναντι στις χαλαρές συγκρίσεις;**  
Όχι. Το strict_types ελέγχει αν οι βαθμωτοί τύποι μετατρέπονται αυτόματα σε κλήσεις συναρτήσεων και τιμές επιστροφής. Στους τελεστές σύγκρισης == και != δεν έχει καμία επίδραση.

**Πώς συγκρίνω σωστά κωδικούς και tokens;**  
Τους κωδικούς τους ελέγχετε με το password_verify, τα tokens και τις υπογραφές με το hash_equals. Και τα δύο συγκρίνουν ακριβώς και, στο hash_equals, σε σταθερό χρόνο. Μια σύγκριση με == ή strcmp είναι ακατάλληλη γι' αυτό.

## Πηγές

- [Εγχειρίδιο της PHP: τελεστές σύγκρισης](https://www.php.net/manual/de/language.operators.comparison.php)
- [Εγχειρίδιο της PHP: match](https://www.php.net/manual/de/control-structures.match.php)
- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/)
