DEV Community

nikosst
nikosst

Posted on

Το Ταξίδι του JWT Όταν η Εμπιστοσύνη Γίνεται Token


Η διαχείριση της σύνδεσης των χρηστών σε εφαρμογές υπήρξε πάντα μια δύσκολη υπόθεση. Παραδοσιακά, χρησιμοποιούνται cookies, sessions και διάφορες μορφές state management για να θυμάται ο server ποιος είναι συνδεδεμένος. Τα cookies αποθηκεύουν μικρά δεδομένα στον browser του χρήστη και στέλνονται αυτόματα με κάθε αίτημα. Τα sessions κρατούν πληροφορίες στη μνήμη ή στη βάση του server, συνδέοντας κάθε χρήστη με ένα μοναδικό session ID. Το state management βοηθά την εφαρμογή να θυμάται σε ποιο σημείο βρίσκεται ο χρήστης, αλλά η συντήρηση όλων αυτών των μηχανισμών μπορεί να γίνει σύνθετη και εύθραυστη, ειδικά όταν υπάρχουν πολλά endpoints, microservices ή περιβάλλοντα που αλλάζουν συχνά.

Το JWT (JSON Web Token) ήρθε να απλοποιήσει αυτή τη διαδικασία, προσφέροντας έναν διαφορετικό τρόπο να εκφράζεται η εμπιστοσύνη ανάμεσα σε client και server. Αντί ο server να χρειάζεται να “θυμάται” κάθε χρήστη, εκδίδει ένα token που περιέχει όλες τις απαραίτητες πληροφορίες μέσα του, με τρόπο ασφαλή και επαληθεύσιμο.


Το σώμα του token και πώς λειτουργεί

Κάθε JWT αποτελείται από τρία μέρη, το Header, το Payload και την Signature. Το Header δηλώνει τον τύπο του token και τον αλγόριθμο υπογραφής που χρησιμοποιείται. Το Payload περιέχει τα claims, δηλαδή τα δεδομένα που περιγράφουν την ταυτότητα και τα δικαιώματα του χρήστη, για παράδειγμα ποιος είναι ο χρήστης (Subject), ποιος εξέδωσε το token (Issuer), ποιοι είναι οι παραλήπτες του (Audience), πότε δημιουργήθηκε (Issued At) και πότε λήγει (Expiration Time). Η Signature είναι η ψηφιακή υπογραφή που εξασφαλίζει ότι το token δεν έχει τροποποιηθεί μετά την έκδοσή του.

Όταν ο χρήστης κάνει login, ο server επαληθεύει τα στοιχεία του, όπως όνομα χρήστη και κωδικό πρόσβασης. Αν αυτά είναι σωστά, δημιουργεί το JWT, παίρνει τα δεδομένα που θέλει να ενσωματώσει στο Payload, τα κωδικοποιεί σε Base64URL, προσθέτει το Header και στη συνέχεια υπογράφει το αποτέλεσμα με ένα μυστικό ή ιδιωτικό κλειδί. Το αποτέλεσμα είναι ένα ενιαίο string που μοιάζει κάπως έτσι:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNjg4MDAwMDAwfQ
.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Enter fullscreen mode Exit fullscreen mode

Αυτό το token αποστέλλεται πίσω στον client, ο οποίος το αποθηκεύει — συνήθως στη μνήμη της εφαρμογής ή σε ένα ασφαλές cookie. Από εκεί και πέρα, κάθε φορά που ο client θέλει να καλέσει ένα προστατευμένο endpoint, στέλνει το token στο HTTP header με τη μορφή Authorization: Bearer . Η λέξη Bearer σημαίνει “κάτοχος” δηλαδή όποιος κρατάει αυτό το token, θεωρείται ότι έχει δικαίωμα να το χρησιμοποιήσει. Για αυτόν τον λόγο είναι κρίσιμο να προστατεύεται από διαρροές, καθώς δίνει πρόσβαση στο σύστημα όσο παραμένει έγκυρο.

Όταν ο server λάβει ένα αίτημα με ένα JWT (JSON Web Token), μπορεί να το επαληθεύσει χωρίς να χρειάζεται να κοιτάξει σε βάση ή cache. Αυτό σημαίνει ότι δεν κρατά καμία αποθηκευμένη πληροφορία για το ποιος είναι συνδεδεμένος όλες οι απαραίτητες πληροφορίες βρίσκονται ήδη μέσα στο token, όπως το user ID, οι ρόλοι του χρήστη και η ημερομηνία λήξης του token.

Το μυστικό ή το δημόσιο κλειδί που χρειάζεται για να επαληθευτεί η υπογραφή του token πρέπει να είναι ήδη γνωστό στον server. Αν χρησιμοποιούμε symmetric signing (π.χ. HS256), το server γνωρίζει το secret key. Αν χρησιμοποιούμε asymmetric signing (π.χ. RS256, που είναι το συνηθισμένο με Auth0), ο server γνωρίζει το public key που παρέχει ο πάροχος ταυτότητας (όπως το Auth0). Με αυτόν τον τρόπο, ο server μπορεί να ελέγξει ότι το token δεν έχει αλλοιωθεί και ότι είναι έγκυρο, χωρίς να χρειάζεται να ανατρέξει στη βάση δεδομένων για να βρει τον χρήστη.

Αν οι έλεγχοι υπογραφής και ημερομηνίας λήξης περάσουν, το αίτημα γίνεται αποδεκτό. Αυτή η λογική ονομάζεται stateless authentication, επειδή δεν απαιτεί καμία αποθήκευση κατάστασης στον server — όλα τα στοιχεία για την ταυτοποίηση του χρήστη περιέχονται ήδη μέσα στο token.

Η προσέγγιση αυτή ταιριάζει ιδανικά σε περιβάλλοντα serverless, όπου δεν υπάρχει μόνιμος server που τρέχει και διατηρεί μνήμη. Σε ένα serverless περιβάλλον, κάθε αίτημα μπορεί να εξυπηρετείται από μια ανεξάρτητη συνάρτηση ή μικροϋπηρεσία που ενεργοποιείται προσωρινά. Το JWT λειτουργεί σαν διαβατήριο, η συνάρτηση μπορεί να επαληθεύσει το token επιτόπου, χωρίς να χρειάζεται να συνδεθεί σε βάση ή να “θυμηθεί” προηγούμενες συνεδρίες.


Η λεπτή ισορροπία ασφάλειας

Το JWT δεν είναι μαγική λύση, η ασφάλειά του εξαρτάται από τη σωστή χρήση. Το Payload δεν είναι κρυπτογραφημένο, μόνο κωδικοποιημένο, επομένως οποιοσδήποτε μπορεί να δει τα περιεχόμενά του. Δεν πρέπει να περιλαμβάνονται ευαίσθητα δεδομένα όπως κωδικοί ή προσωπικές πληροφορίες. Η πραγματική προστασία βρίσκεται στην υπογραφή, η οποία διασφαλίζει ότι το token δεν έχει τροποποιηθεί και ότι προέρχεται πράγματι από τον αξιόπιστο εκδότη.

Επιπλέον, τα access tokens πρέπει να έχουν μικρή διάρκεια ζωής. Όταν λήγουν, χρησιμοποιούνται refresh tokens για την έκδοση νέων. Τα refresh tokens έχουν μεγαλύτερη διάρκεια, αλλά πρέπει να φυλάσσονται με αυστηρότητα και να ανανεώνονται περιοδικά, μια διαδικασία που ονομάζεται token rotation. Αυτή η πρακτική μειώνει τον κίνδυνο επαναχρησιμοποίησης σε περίπτωση παραβίασης.


Από τα sessions στα tokens μια αλλαγή φιλοσοφίας

Με τα sessions, η αυθεντικοποίηση βασίζεται στη διατήρηση κατάστασης στον server κάτι που γίνεται περίπλοκο όταν υπάρχουν πολλοί servers ή microservices. Με τα tokens, η ευθύνη μεταφέρεται στον client, ο χρήστης κουβαλάει μαζί του την ταυτότητά του, υπογεγραμμένη από τον server. Κάθε υπηρεσία που γνωρίζει το δημόσιο κλειδί του εκδότη μπορεί να επαληθεύσει το JWT χωρίς να εξαρτάται από κάποια κοινή βάση δεδομένων. Το αποτέλεσμα είναι ένα αποκεντρωμένο, καθαρό και επεκτάσιμο σύστημα που στηρίζεται στην κρυπτογραφική εμπιστοσύνη αντί στη μνήμη του server.


Το τέλος του ταξιδιού

Το JWT είναι σαν διαβατήριο που δεν χρειάζεται γραφειοκρατία. Το κρατάς, το δείχνεις, ο server σε αναγνωρίζει και συνεχίζεις. Όμως, όπως κάθε διαβατήριο, έχει ημερομηνία λήξης και πρέπει να προστατεύεται. Η χρήση του σημαίνει απλότητα, αλλά και υπευθυνότητα ένα σύστημα που δεν χρειάζεται να “θυμάται” για να εμπιστευτεί.

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

Μπορούμε να το φανταστούμε σαν μια ψηφιακή ταυτότητα που κρατάς στα χέρια σου. Όπως ένας άνθρωπος δείχνει την ταυτότητά του για να εισέλθει σε ένα συνέδριο πληροφορικής, να αποδείξει την ηλικία του σε ένα μπαρ ή να περάσει από έναν έλεγχο ασφαλείας, έτσι και το JWT λειτουργεί ως απόδειξη ταυτότητας για τις εφαρμογές. Δεν χρειάζεται κάποιος να καλέσει μια αρχή για να επιβεβαιώσει την εγκυρότητα η υπογραφή πάνω του το αποδεικνύει. Το μόνο που μένει είναι να το δείξεις εκεί που χρειάζεται. Είναι η ίδια πράξη εμπιστοσύνης, απλώς σε ψηφιακή μορφή, μια ταυτότητα που δεν την κρατάει το κράτος, αλλά η εφαρμογή σου.


nikosstit@gmail.com

Top comments (0)