JWT vs Session: ποιον μηχανισμό ταυτοποίησης να επιλέξετε;
Η ταυτοποίηση ενός χρήστη σημαίνει να γνωρίζετε σε κάθε αίτημα ποιος είναι. Δύο μεγάλες οικογένειες αντιπαρατίθενται: οι συνεδρίες διακομιστή, όπου ο διακομιστής κρατά το ίχνος του συνδεδεμένου χρήστη, και τα JSON Web Tokens (JWT), όπου η ταυτότητα ταξιδεύει μέσα σε ένα υπογεγραμμένο διακριτικό που μεταφέρει ο πελάτης. Η επιλογή επηρεάζει την ασφάλεια, την ικανότητα κλιμάκωσης και την ευκολία αποσύνδεσης ενός χρήστη. Δείτε πώς να αποφασίσετε ανάλογα με το πλαίσιό σας.
Οι συνεδρίες διακομιστή (stateful)
Με μια συνεδρία, ο διακομιστής δημιουργεί ένα αναγνωριστικό συνεδρίας κατά τη σύνδεση, αποθηκεύει τα σχετικά δεδομένα (ταυτότητα, ρόλοι, καλάθι) στην πλευρά του διακομιστή (μνήμη, Redis, βάση δεδομένων) και επιστρέφει στον περιηγητή ένα cookie που περιέχει μόνο αυτό το αναγνωριστικό. Σε κάθε αίτημα, ο διακομιστής διαβάζει το cookie, βρίσκει τη συνεδρία και γνωρίζει ποιος μιλά.
- Κατάσταση στην πλευρά του διακομιστή: η πηγή της αλήθειας παραμένει στον διακομιστή, ο πελάτης μεταφέρει μόνο μια αδιαφανή αναφορά.
- Άμεση ανάκληση: η διαγραφή της συνεδρίας στην πλευρά του διακομιστή αποσυνδέει ακαριαία τον χρήστη.
- Cookie: μεταδίδεται αυτόματα από τον περιηγητή, ιδανικά με
HttpOnly,SecureκαιSameSite.
Τα JSON Web Tokens (stateless)
Ένα JWT είναι ένα αυτοφερόμενο διακριτικό που αποτελείται από τρία μέρη κωδικοποιημένα σε base64url και διαχωρισμένα με τελείες: ένα header, ένα payload (τα claims, για παράδειγμα το αναγνωριστικό του χρήστη και τη λήξη) και μια υπογραφή. Ο διακομιστής υπογράφει το διακριτικό κατά τη σύνδεση: στη συνέχεια του αρκεί να επαληθεύσει την υπογραφή για να εμπιστευτεί το περιεχόμενο, χωρίς να αποθηκεύσει τίποτα.
- Χωρίς κατάσταση: όλη η απαραίτητη πληροφορία βρίσκεται μέσα στο διακριτικό, ο διακομιστής δεν χρειάζεται κοινόχρηστη μνήμη.
- Επαληθεύσιμο παντού: οποιαδήποτε υπηρεσία γνωρίζει το κλειδί μπορεί να επικυρώσει το διακριτικό, πρακτικό για κατανεμημένες αρχιτεκτονικές και SSO.
- Εργαλεία: μπορείτε να επιθεωρήσετε ένα διακριτικό με τον αποκωδικοποιητή JWT, να ελέγξετε την υπογραφή του με τον επαληθευτή JWT ή να δημιουργήσετε ένα με τη γεννήτρια JWT.
Συγκριτικός πίνακας
| Κριτήριο | Συνεδρία διακομιστή | JWT |
|---|---|---|
| Κατάσταση | Stateful (αποθηκευμένη στον διακομιστή) | Stateless (μεταφέρεται από τον πελάτη) |
| Αποθήκευση στον διακομιστή | Απαιτείται (Redis, βάση) | Καμία |
| Ανάκληση | Άμεση | Δύσκολη πριν τη λήξη |
| Οριζόντια κλιμακωσιμότητα | Απαιτείται κοινόχρηστος store | Εγγενής |
| Μεταδιδόμενο μέγεθος | Μικρό (ένα αναγνωριστικό) | Μεγαλύτερο (υπογεγραμμένα claims) |
| Διαδικτυακή / SSO | Περιοριστική | Κατάλληλη |
| Επιφάνεια XSS | Χαμηλή με cookie HttpOnly | Υψηλή αν αποθηκευτεί σε localStorage |
Ασφάλεια: XSS, CSRF και ανάκληση
Και οι δύο προσεγγίσεις είναι ασφαλείς εφόσον υλοποιηθούν σωστά, αλλά οι κίνδυνοί τους διαφέρουν.
- XSS: ένα cookie συνεδρίας
HttpOnlyείναι απρόσιτο στη JavaScript, άρα προστατευμένο από κλοπή μέσω injection. Ένα JWT αποθηκευμένο σεlocalStorageείναι αντιθέτως αναγνώσιμο από κάθε script, γεγονός που το καθιστά πρώτης τάξεως στόχο. Η αποθήκευση του JWT σε ένα cookieHttpOnlyακυρώνει αυτό το πλεονέκτημα του JWT αλλά επανεισάγει τον κίνδυνο CSRF. - CSRF: τα cookies αποστέλλονται αυτόματα, άρα είναι ευάλωτα στο CSRF χωρίς προστασία (χαρακτηριστικό
SameSite, διακριτικό anti-CSRF). Ένα JWT που αποστέλλεται χειροκίνητα στην κεφαλίδαAuthorizationδεν επηρεάζεται. - Ανάκληση: αυτό είναι το αδύναμο σημείο του JWT. Καθώς είναι αυτοφερόμενο, δεν μπορεί να ακυρωθεί πριν τη λήξη του χωρίς να επανεισαχθεί μια κατάσταση διακομιστή (λίστα ανάκλησης, blacklist). Μια συνεδρία διαγράφεται ακαριαία.
Κλιμακωσιμότητα και αρχιτεκτονική
Σε έναν μόνο διακομιστή, οι συνεδρίες είναι ασήμαντες. Μόλις κατανείμετε το φορτίο σε πολλές εμφανίσεις, κάθε εμφάνιση πρέπει να έχει πρόσβαση στις συνεδρίες: χρειάζεται ένας κοινόχρηστος store (Redis) ή sticky sessions. Το JWT λάμπει εδώ, καθώς οποιαδήποτε εμφάνιση επικυρώνει το διακριτικό χωρίς κλήση δικτύου ούτε κοινή αποθήκευση.
- Microservices: ένα JWT διαδίδει την ταυτότητα από τη μία υπηρεσία στην άλλη χωρίς κεντρική βάση.
- Δημόσια και κινητά API: το JWT αποφεύγει τη διαχείριση cookies στην πλευρά του εγγενούς πελάτη.
- Κλασικός μονόλιθος: η συνεδρία παραμένει απλούστερη και ασφαλέστερη εξ ορισμού.
Πότε να επιλέξετε το ένα ή το άλλο
Επιλέξτε τις συνεδρίες όταν
- Αναπτύσσετε μια κλασική διαδικτυακή εφαρμογή με απόδοση στον διακομιστή
- Η άμεση ανάκληση είναι κρίσιμη (τράπεζα, υγεία, back-office)
- Θέλετε την ασφαλέστερη εξ ορισμού λύση, με τις λιγότερες παγίδες
- Η υποδομή σας αντέχει έναν κοινόχρηστο store συνεδριών χωρίς δυσκολία
Επιλέξτε το JWT όταν
- Εκθέτετε ένα API που καταναλώνεται από SPA, κινητά ή τρίτους
- Έχετε αρχιτεκτονική microservices ή SSO μεταξύ domains
- Πρέπει να κλιμακώσετε οριζόντια χωρίς κοινόχρηστο store
- Δέχεστε να διαχειριστείτε τη σύντομη λήξη και την ανανέωση των διακριτικών
Σύσταση
Για την πλειονότητα των διαδικτυακών εφαρμογών, οι συνεδρίες διακομιστή παραμένουν η ασφαλέστερη και απλούστερη επιλογή: άμεση ανάκληση, cookie HttpOnly και μηδενική διαχείριση διακριτικού στην πλευρά του πελάτη. Κρατήστε το JWT για τις περιπτώσεις όπου η απουσία κατάστασης προσφέρει πραγματική αξία: stateless API, κινητά, microservices, SSO.
Αν επιλέξετε το JWT, διατηρήστε μια σύντομη διάρκεια ζωής (μερικά λεπτά) σε συνδυασμό με ένα refresh token αποθηκευμένο σε cookie HttpOnly, και προβλέψτε μια λίστα ανάκλησης για τις ευαίσθητες περιπτώσεις. Έτσι συνδυάζετε το καλύτερο και των δύο κόσμων.
Συχνές ερωτήσεις
Είναι κρυπτογραφημένο ένα JWT;
Όχι, εξ ορισμού ένα JWT είναι μόνο υπογεγραμμένο, όχι κρυπτογραφημένο. Το payload του είναι κωδικοποιημένο σε base64url και αναγνώσιμο από οποιονδήποτε το υποκλέψει. Μην τοποθετείτε ποτέ ευαίσθητα δεδομένα σε καθαρή μορφή μέσα σε ένα JWT. Για να κρυπτογραφήσετε το περιεχόμενο, πρέπει να καταφύγετε στο JWE (JSON Web Encryption).
Πού να αποθηκεύσετε ένα JWT στην πλευρά του πελάτη;
Το ασφαλέστερο είναι ένα cookie HttpOnly, Secure και SameSite, που προστατεύει από κλοπή μέσω XSS. Το localStorage είναι απλούστερο αλλά εκθέτει το διακριτικό σε κάθε κακόβουλο script. Αποφύγετέ το για διακριτικά υψηλών προνομίων.
Πώς να αποσυνδέσετε έναν χρήστη με ένα JWT;
Καθώς το διακριτικό είναι αυτοφερόμενο, η πραγματική αποσύνδεση απαιτεί είτε την αναμονή της λήξης του, είτε τη διατήρηση μιας λίστας ανάκλησης στην πλευρά του διακομιστή. Γι' αυτό χρησιμοποιούμε σύντομες διάρκειες ζωής και ένα refresh token που μπορεί να ανακληθεί.
Μπορούμε να συνδυάσουμε συνεδρίες και JWT;
Ναι, είναι μια συνηθισμένη πρακτική: ένα access token JWT σύντομης διάρκειας ζωής για τις κλήσεις API, και ένα refresh token που διαχειρίζεται σαν συνεδρία (αποθηκευμένο και ανακλήσιμο στην πλευρά του διακομιστή) για την ανανέωση του access token.