Ανάπτυξη λογισμικού
Επιθέσεις χρονισμού στην PHP: Γιατί η `hash_equals()` έχει σημασία
Θα θέλατε ένα ρεαλιστικό παράδειγμα επίθεσης χρονισμού σε tokens API στο Wordpress/Laravel/PHP; Το καλύπτουμε εδώ, συμπεριλαμβανομένων συμβουλών και μέτρων βέλτιστης πρακτικής κατά των επιθέσεων χρονισμού.
Πολλοί προγραμματιστές βασίζονται στην απλή σύγκριση με τη χρήση === ή == όταν ελέγχουν κλειδιά API, tokens ή άλλες μυστικές συμβολοσειρές. Με την πρώτη ματιά, αυτό φαίνεται λογικό - αλλά υπάρχει μια παγίδα: οι χρονικές διαφορές στη σύγκριση μπορούν να αξιοποιηθούν από τους επιτιθέμενους.
Αυτό το άρθρο περιγράφει ένα ρεαλιστικό παράδειγμα του πώς λειτουργεί εννοιολογικά μια επίθεση χρονισμού.
Το πραγματικό σενάριο (απλουστευμένο παράδειγμα)
Φανταστείτε ότι μια εσωτερική μικρουπηρεσία δέχεται αιτήσεις με ένα token παραμέτρου ερώτησης και το συγκρίνει με ένα token API του GitHub που είναι αποθηκευμένο στο περιβάλλον.
Ανασφαλής κώδικας (απλουστευμένο):
$expected = getenv('GITHUB_API_TOKEN');$provided = $_GET['token'] ?? '';if ($provided === $expected) { } PHP
Θα εξηγήσω γιατί αυτό είναι προβληματικό στην επόμενη ενότητα.
Πώς λειτουργεί μια επίθεση χρονισμού;
Αν η υλοποίηση της σύγκρισης token συγκρίνει χαρακτήρα προς χαρακτήρα και διακόπτει αμέσως στο πρώτο λάθος, τότε μια αίτηση με τον σωστό πρώτο χαρακτήρα διαρκεί λίγο περισσότερο κατά μέσο όρο.
Επομένως, ένας σωστός πρώτος χαρακτήρας οδηγεί κατά μέσο όρο σε ελαφρώς μεγαλύτερο χρόνο επεξεργασίας από ό,τι ένας λανθασμένος πρώτος χαρακτήρας. Το ίδιο ισχύει και για τον δεύτερο χαρακτήρα κ.ο.κ.
Ένας επιτιθέμενος εκμεταλλεύεται αυτό το γεγονός δοκιμάζοντας όλους τους πιθανούς χαρακτήρες για κάθε θέση, μετρώντας τους χρόνους απόκρισης πολύ συχνά και αναλύοντάς τους στατιστικά. Ο χαρακτήρας με τον μεγαλύτερο μέσο όρο/αναλογικά μεγαλύτερο χρόνο είναι πιθανότατα σωστός. Με αυτόν τον τρόπο, το σύμβολο ανακατασκευάζεται βήμα προς βήμα.
Γιατί η hash_equals() είναι η σωστή επιλογή
Η PHP παρέχει μια συνάρτηση σύγκρισης συμβολοσειρών σε σταθερό χρόνο με την hash_equals(). Εξασφαλίζει ότι ο χρόνος εκτέλεσης της σύγκρισης δεν εξαρτάται από κοινά προθέματα - εφόσον και οι δύο συμβολοσειρές έχουν το ίδιο μήκος.
Ασφαλής εναλλακτική λύση (για Laravel, PHP, Wordpress):
$expected = getenv('GITHUB_API_TOKEN'); $provided = $_GET['token'] ?? '';if (hash_equals($expected, $provided)) { } PHP
Σημείωση: η hash_equals() είναι "ανεξάρτητη από το χρόνο" μόνο αν τα μήκη είναι ίσα. Είναι καλή πρακτική να σχεδιάζετε tokens έτσι ώστε το μήκος να είναι σταθερό (π.χ. HMACs, UUIDs σταθερού μήκους ή τυχαίες συμβολοσειρές Base64 σταθερού μήκους).
Το γνωρίζατε; Μόνο το UUID-V4 παράγεται εντελώς τυχαία και επομένως χρησιμοποιείται συχνά για μάρκες ασφαλείας. Επειδή δεν περιέχει πληροφορίες που σχετίζονται με τον χρόνο ή τη συσκευή, προσφέρει υψηλό επίπεδο απρόβλεπτου και συνεπώς προστατεύει από επιθέσεις που βασίζονται σε μοτίβα ή προβλέψεις. Αυτός ακριβώς είναι ο λόγος για τον οποίο το UUID-V4 είναι η προτιμώμενη επιλογή όταν πρόκειται για ασφαλή, δύσκολα αναγνωρίσιμα αναγνωριστικά.
Πρόσθετα μέτρα άμυνας - περισσότερα από την hash_equals()
- Σταθερό μήκος συμβόλου
Χρησιμοποιήστε tokens με σταθερό μήκος, π.χ. UUID-V4. Εάν ένας επιτιθέμενος μαντέψει το μήκος, αυτό είναι λιγότερο χρήσιμο εφόσον οι ίδιοι οι χαρακτήρες είναι ασφαλείς.
- Περιορισμός ρυθμού
Περιορίστε τις αιτήσεις ανά IP ή ανά λογαριασμό. Οι επιθέσεις χρονισμού απαιτούν πολλές μετρήσεις- ο περιορισμός του ρυθμού αυξάνει σημαντικά την προσπάθεια και το κόστος για τον επιτιθέμενο.
- Καταγραφή και παρακολούθηση
Αναγνωρίστε ασυνήθιστα μοτίβα (πολλές προσπάθειες token, συστηματική μεταβολή ορισμένων παραμέτρων) και αντιδράστε αυτόματα.
- Αλάτι / HMAC / υπογραφές
Χρησιμοποιήστε υπογεγραμμένα tokens (HMAC με μυστικό κλειδί) ή tokens OAuth αντί της ανοιχτής σύγκρισης ακατέργαστων στατικών κλειδιών.
- TLS/HTTPS
Η κρυπτογράφηση προστατεύει τα κανάλια επικοινωνίας - αν και δεν αποτρέπει τις επιθέσεις χρονισμού στα εσωτερικά του διακομιστή, αποτελεί βασική απαίτηση.
- Περιστροφή των διακριτικών
Η σύντομη διάρκεια ζωής των token μειώνει το όφελος από ένα συμβιβασμένο token.
Συμπέρασμα
Οι επιθέσεις χρονισμού δεν είναι ένα καθαρά θεωρητικό πρόβλημα - έχουν διερευνηθεί στην πράξη και μπορούν να έχουν σοβαρές συνέπειες, ιδίως για τα δημόσια προσβάσιμα τελικά σημεία. Τα καλά νέα: Για τους προγραμματιστές PHP/Laravel/Wordpress, το πρώτο αντίμετρο είναι πολύ απλό:
- Αντικαταστήστε τις άμεσες συγκρίσεις ευαίσθητων συμβολοσειρών με την
hash_equals().
- Εξασφαλίστε σταθερά μήκη token, περιορισμό ρυθμού, καταγραφή και ασφαλή διαχείριση token.