Web Security – Part 2: Από τα Passkeys και τις ψηφιακές υπογραφές μέχρι τα JWT και το OAuth 2.0

Πώς αποδεικνύουμε την ταυτότητά μας, πώς λειτουργούν τα κρυπτογραφικά κλειδιά και πώς αποκτούν εφαρμογές ασφαλή πρόσβαση σε άλλες υπηρεσίες; Στο πρώτο μέρος της σειράς Web Security  εξετάσαμε τους βασικούς μηχανισμούς προστασίας μιας διαδικτυακής εφαρμογής. Μιλήσαμε για κρυπτογράφηση, hashing, authentication, authorization, SQL Injection, XSS, CSRF και ασφαλή διαχείριση sessions. Στο δεύτερο μέρος προχωράμε βαθύτερα στον τρόπο με τον οποίο οι εφαρμογές επαληθεύουν ταυτότητες και διαχειρίζονται την πρόσβαση. Θα γνωρίσουμε τις ψηφιακές υπογραφές, τα Passkeys, τα JSON Web Tokens (JWT), το OAuth 2.0 και το OpenID Connect. Στόχος δεν είναι να απομνημονεύσουμε ορολογίες, αλλά να κατανοήσουμε γιατί χρειάζεται κάθε μηχανισμός.

Δημοσιογραφική Ομάδα CodeCraft.gr 11′ ανάγνωση

Web Security – Part 2: Από τα Passkeys και τις ψηφιακές υπογραφές μέχρι τα JWT και το OAuth 2.0

1. Timing Attacks:  Όταν ο χρόνος αποκαλύπτει πληροφορίες

Ακόμη και μια εφαρμογή που δεν εμφανίζει ευαίσθητες πληροφορίες μπορεί να αποκαλύπτει στοιχεία μέσω της συμπεριφοράς της.

Ένα παράδειγμα είναι ο διαφορετικός χρόνος απόκρισης κατά τη διαδικασία σύνδεσης.

Παράδειγμα

Ένας χρήστης προσπαθεί να κάνει login με δύο διαφορετικά usernames.

  • giorgos: Ο server απαντά σε 300 ms.

  • kostas: Ο server απαντά σε 10 ms.

Η διαφορά μπορεί να οφείλεται στο ότι ο Γιώργος υπάρχει στη βάση και εκτελείται έλεγχος password. Αντίθετα, για τον Κώστα η εφαρμογή επιστρέφει αμέσως επειδή δεν βρίσκει τον λογαριασμό.

Ένας εισβολέας μπορεί να επαναλάβει πολλές φορές τα requests και να εξετάσει τους χρόνους. Με αυτόν τον τρόπο ενδέχεται να ανακαλύψει ποιοι λογαριασμοί υπάρχουν.

Πώς προστατευόμαστε;

Μια τεχνική είναι να εκτελούμε παρόμοια υπολογιστική εργασία ακόμη και όταν ο λογαριασμός δεν υπάρχει. Για παράδειγμα, μπορούμε να χρησιμοποιήσουμε ένα προκαθορισμένο εικονικό password hash με τον Argon2id.

Η τεχνική αυτή μειώνει τις χρονικές διαφορές, χωρίς να εγγυάται απόλυτα ίσους χρόνους. Συνδυάζεται με περιορισμούς αιτημάτων και άλλους ελέγχους ασφαλείας.

2. MFA : Περισσότερο από ένα Password

Το Multi-Factor Authentication (MFA) σημαίνει Πολυπαραγοντική Ταυτοποίηση.

Η βασική ιδέα είναι να μην εξαρτάται η σύνδεση αποκλειστικά από ένα password. Χρησιμοποιούμε περισσότερες από μία ανεξάρτητες κατηγορίες αποδεικτικών στοιχείων.

Οι βασικές κατηγορίες είναι:

  • Κάτι που γνωρίζουμε: Password ή PIN.

  • Κάτι που κατέχουμε: Κινητό ή φυσικό security key.

  • Κάτι που είμαστε: Βιομετρικό χαρακτηριστικό, όπως δακτυλικό αποτύπωμα.

Δύο passwords δεν αποτελούν πραγματικό MFA, επειδή ανήκουν στην ίδια κατηγορία.

Παράδειγμα

Ο Γιώργος πληκτρολογεί το password του και στη συνέχεια έναν εξαψήφιο κωδικό από εφαρμογή Authenticator.

Ο κωδικός μπορεί να παράγεται με τον αλγόριθμο TOTP (Time-based One-Time Password). Συνήθως αλλάζει κάθε 30 δευτερόλεπτα, περιορίζοντας το χρονικό διάστημα κατά το οποίο μπορεί να χρησιμοποιηθεί.

Ωστόσο, ένας εισβολέας μπορεί ακόμη να υποκλέψει έναν έγκυρο κωδικό μέσω phishing. Επομένως, ούτε αυτή η μέθοδος εξαλείφει κάθε κίνδυνο.

3. Passkeys : Σύνδεση χωρίς παραδοσιακό Password

Τα Passkeys χρησιμοποιούν ασύμμετρη κρυπτογραφία και αποτελούν έναν πιο ανθεκτικό στο phishing τρόπο ταυτοποίησης.

Αντί να μοιράζεται ένας χρήστης ένα μυστικό password με την εφαρμογή, χρησιμοποιείται ζεύγος κρυπτογραφικών κλειδιών.

  • Private Key: Παραμένει προστατευμένο στη συσκευή ή στο σύστημα διαχείρισης Passkeys.

  • Public Key: Καταχωρίζεται στον server της εφαρμογής.

Παράδειγμα

Ο Γιώργος θέλει να συνδεθεί στο CodeCraft.gr.

  1. Ο server δημιουργεί έναν τυχαίο αριθμό, το Challenge.

  2. Η συσκευή χρησιμοποιεί το Private Key για να δημιουργήσει ψηφιακή υπογραφή.

  3. Ο browser στέλνει την υπογραφή και τα απαιτούμενα στοιχεία στον server.

  4. Ο server επαληθεύει την απάντηση με το αποθηκευμένο Public Key.

Το Private Key δεν χρειάζεται να μεταφερθεί στον server.

Γιατί προστατεύει από το phishing;

Τα Passkeys συνδέονται με την ταυτότητα της πραγματικής ιστοσελίδας, γνωστή ως Relying Party ID.

Ένα Passkey καταχωρισμένο για το codecraft.gr δεν μπορεί κανονικά να χρησιμοποιηθεί από ένα άσχετο domain όπως το codecraft-login.gr.

4. Public και Private Keys : Ποιος κρατά ποιο κλειδί;

Στην ασύμμετρη κρυπτογραφία χρησιμοποιούμε δύο μαθηματικά συνδεδεμένα κλειδιά.

Το Public Key μπορεί να είναι δημόσιο, ενώ το Private Key πρέπει να προστατεύεται από τον κάτοχό του.

Δεν υπάρχει κανόνας ότι ο client κρατά πάντοτε το Private Key. Εξαρτάται από τον σκοπό της επικοινωνίας.

Παράδειγμα Α — Passkey

Ο χρήστης διαθέτει το Private Key και ο server γνωρίζει το Public Key. Ο χρήστης υπογράφει και ο server επαληθεύει.

Παράδειγμα Β — HTTPS

Ο server διαθέτει το Private Key του πιστοποιητικού του και ο browser λαμβάνει το αντίστοιχο Public Key. Στο σύγχρονο TLS, ο server αποδεικνύει την κατοχή του Private Key υπογράφοντας συγκεκριμένα δεδομένα της σύνδεσης.

Τα πιστοποιητικά και οι έμπιστες Αρχές Πιστοποίησης (CA) βοηθούν τον browser να συνδέσει το Public Key με το σωστό domain.

5. Digital Signatures : Τι είναι πραγματικά η ψηφιακή υπογραφή;

Η ψηφιακή υπογραφή (Digital Signature) είναι ένα κρυπτογραφικό αποτέλεσμα που παράγεται χρησιμοποιώντας το Private Key.

Ο παραλήπτης μπορεί να ελέγξει την υπογραφή χρησιμοποιώντας το αντίστοιχο Public Key.

Η υπογραφή επιτρέπει να επαληθεύσουμε ότι ένα μήνυμα δεν αλλοιώθηκε και ότι χρησιμοποιήθηκε το συγκεκριμένο Private Key. Η σύνδεση αυτού του κλειδιού με μια πραγματική ταυτότητα απαιτεί επιπλέον εμπιστοσύνη και ελέγχους.

Παράδειγμα

Η Μαρία θέλει να σου στείλει ένα υπογεγραμμένο μήνυμα.

  • Η Μαρία υπογράφει με το δικό της Private Key.

  • Εσύ επαληθεύεις με το Public Key της Μαρίας.

Αν θέλει το μήνυμα να είναι και εμπιστευτικό, χρειάζεται επιπλέον κρυπτογράφηση.

Υπογραφή και κρυπτογράφηση δεν είναι το ίδιο

Η κρυπτογράφηση προστατεύει την εμπιστευτικότητα ενός μηνύματος. Η ψηφιακή υπογραφή προστατεύει την ακεραιότητά του και αποδεικνύει τη χρήση συγκεκριμένου ιδιωτικού κλειδιού.

Στο εκπαιδευτικό RSA, η βασική μαθηματική πράξη υπογραφής έχει τη μορφή:

S = M^d mod N

Όπου:

  • M: Ο αριθμός που αναπαριστά τα προς υπογραφή δεδομένα, μετά την κατάλληλη επεξεργασία.

  • d: Ο ιδιωτικός εκθέτης.

  • N: Το γινόμενο δύο μεγάλων πρώτων αριθμών.

  • S: Η υπογραφή.

Στο πραγματικό RSA-PSS προηγείται ασφαλής κωδικοποίηση του hash του μηνύματος, με χρήση τυχαίου salt.

Το σημαντικό είναι ότι το Private Key δημιουργεί την υπογραφή, ενώ το Public Key την επαληθεύει.

6. JWT : JSON Web Tokens

Το JWT (JSON Web Token) είναι ένας τυποποιημένος τρόπος μεταφοράς πληροφοριών μεταξύ συστημάτων.

Ένα συνηθισμένο υπογεγραμμένο JWT αποτελείται από τρία μέρη:

HEADER . PAYLOAD . SIGNATURE

  • Header: Περιγράφει, μεταξύ άλλων, τον αλγόριθμο υπογραφής.

  • Payload: Περιλαμβάνει δεδομένα και ισχυρισμούς, γνωστούς ως claims.

  • Signature: Προστατεύει την ακεραιότητα των προηγούμενων μερών.

Παράδειγμα

Ένα JWT μπορεί να περιέχει:

sub = 15, role = editor, exp = χρονική στιγμή λήξης.

Αν ο Γιώργος επιχειρήσει να αλλάξει το role από editor σε admin, η επαλήθευση της υπογραφής θα αποτύχει.

Υπάρχει όμως μια σημαντική λεπτομέρεια.

Ένα συνηθισμένο υπογεγραμμένο JWT δεν είναι κρυπτογραφημένο.

Το Payload μπορεί να διαβαστεί από όποιον αποκτήσει το token. Γι' αυτό δεν τοποθετούμε passwords, μυστικά API keys ή άλλα ευαίσθητα μυστικά μέσα του.

7. Token Expiration και Revocation

Ένα JWT μπορεί να διαθέτει χρόνο λήξης μέσω του πεδίου exp.

Ακόμη κι αν η υπογραφή είναι έγκυρη, ο server πρέπει να απορρίπτει ένα token που έχει λήξει.

Παράδειγμα

Ο Γιώργος αποκτά JWT διάρκειας μίας ώρας και κάνει Logout μετά από δέκα λεπτά.

Η διαγραφή του token από τον browser δεν σημαίνει απαραίτητα ότι το JWT έπαψε να ισχύει.

Αν κάποιος το έχει αντιγράψει, μπορεί να συνεχίσει να το χρησιμοποιεί όσο παραμένει έγκυρο. Αυτό συμβαίνει εφόσον ο server ελέγχει μόνο την υπογραφή και τη λήξη.

Πώς προστατευόμαστε;

Μπορούμε να χρησιμοποιήσουμε έναν μηχανισμό ανάκλησης (Token Revocation).

Ο server καταχωρίζει ότι το συγκεκριμένο token δεν πρέπει πλέον να γίνεται αποδεκτό. Η υλοποίηση αυτή απαιτεί πρόσθετους ελέγχους και κατάλληλη διαχείριση της κατάστασης των tokens.

8. Access Tokens και Refresh Tokens

Ένα Access Token χρησιμοποιείται για να αποκτήσουμε πρόσβαση σε προστατευμένα resources.

Ένα Refresh Token επιτρέπει, όταν προβλέπεται, την έκδοση νέου Access Token χωρίς να απαιτείται κάθε φορά νέο login.

Παράδειγμα

Στις 10:00 ο Γιώργος κάνει Login.

  • Access Token: Ισχύει για 5 λεπτά.

  • Refresh Token: Ισχύει για 7 ημέρες.

Στις 10:05 το Access Token λήγει.

Η εφαρμογή παρουσιάζει το Refresh Token στον κατάλληλο server, ο οποίος το επαληθεύει. Αν όλα είναι σωστά, μπορεί να εκδώσει νέο Access Token.

Πού βρίσκεται ο κίνδυνος;

Αν ένας εισβολέας κλέψει ένα Refresh Token, μπορεί ενδεχομένως να αποκτά νέα Access Tokens. Ο κίνδυνος παραμένει όσο το Refresh Token γίνεται αποδεκτό.

Refresh Token Rotation

Ένας σημαντικός μηχανισμός προστασίας είναι το Refresh Token Rotation.

Κάθε φορά που χρησιμοποιείται ένα Refresh Token, εκδίδεται νέο και το προηγούμενο ακυρώνεται.

Για παράδειγμα:

  • Refresh Token A → Χρησιμοποιείται.

  • Refresh Token B → Εκδίδεται.

  • Refresh Token A → Ακυρώνεται.

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

Ανάλογα με την πολιτική ασφαλείας, μπορεί να ακυρώσει ολόκληρη την οικογένεια των tokens και να απαιτήσει νέα εξουσιοδότηση.

9. OAuth 2.0 : Πρόσβαση χωρίς κοινοποίηση Password

Το OAuth 2.0 είναι ένα πρωτόκολλο εξουσιοδότησης.

Επιτρέπει σε μια εφαρμογή να αποκτά περιορισμένη πρόσβαση σε συγκεκριμένες υπηρεσίες, χωρίς να χρειάζεται το password του χρήστη.

Παράδειγμα

Το CodeCraft.gr θέλει να αποκτήσει πρόσβαση σε επιλεγμένα δεδομένα ενός λογαριασμού Google.

Αντί να ζητήσει το password, κατευθύνει τον χρήστη στη Google. Εκεί ο χρήστης μπορεί να εγκρίνει τα δικαιώματα που ζητά η εφαρμογή.

Στη συνέχεια, το CodeCraft μπορεί να αποκτήσει ένα Access Token με τα εγκεκριμένα δικαιώματα.

Τι είναι τα Scopes;

Τα Scopes εκφράζουν τα δικαιώματα πρόσβασης που ζητά μια εφαρμογή.

Για παράδειγμα, ένα Access Token μπορεί να επιτρέπει την ανάγνωση συγκεκριμένων δεδομένων, αλλά όχι την τροποποίηση ή τη διαγραφή τους.

Τα Scopes δεν αντικαθιστούν τους ελέγχους εξουσιοδότησης του ίδιου του API.

Αν μια εφαρμογή χρειάζεται αργότερα περισσότερα δικαιώματα, πρέπει να ζητήσει νέα εξουσιοδότηση. Δεν μπορεί να προσθέσει αυθαίρετα περισσότερα Scopes σε ένα ήδη εκδομένο Access Token.

10. Authorization Code και PKCE

Στη σύγχρονη ροή OAuth, η εφαρμογή συνήθως λαμβάνει πρώτα έναν προσωρινό Authorization Code.

Στη συνέχεια ανταλλάσσει τον κωδικό με Access Token μέσω κατάλληλου endpoint του παρόχου.

Αυτό βοηθά να αποφεύγεται η απευθείας έκθεση Access Tokens μέσα στα URLs ανακατεύθυνσης.

Τι κάνει το PKCE;

Το PKCE (Proof Key for Code Exchange) προστατεύει την ανταλλαγή του Authorization Code.

Η εφαρμογή δημιουργεί μια τυχαία μυστική τιμή, το Code Verifier.

Στη συνέχεια υπολογίζει το Code Challenge, συνήθως χρησιμοποιώντας SHA-256 και Base64URL.

Παράδειγμα

  1. Το CodeCraft δημιουργεί ένα Code Verifier.

  2. Στέλνει στη Google το Code Challenge.

  3. Η Google εκδίδει Authorization Code.

  4. Το CodeCraft παρουσιάζει το Authorization Code μαζί με το αρχικό Verifier.

  5. Η Google επαληθεύει ότι το Verifier αντιστοιχεί στο αρχικό Challenge.

Αν κάποιος κλέψει μόνο τον Authorization Code, δεν διαθέτει απαραίτητα όσα χρειάζονται για να τον ανταλλάξει.

Το PKCE δεν αποδεικνύει από μόνο του την ταυτότητα του χρήστη. Συνδέει την τελική ανταλλαγή με το αρχικό μυστικό της διαδικασίας.

11. OpenID Connect : Ποιος είναι ο χρήστης;

Το OAuth 2.0 επικεντρώνεται στην εξουσιοδότηση πρόσβασης.

Το OpenID Connect (OIDC) προσθέτει ένα τυποποιημένο επίπεδο ταυτοποίησης πάνω από το OAuth 2.0.

Χρησιμοποιείται σε περιπτώσεις όπως το «Login with Google».

Τι είναι το ID Token;

Το ID Token μεταφέρει πληροφορίες για την ταυτοποίηση του χρήστη. Συνήθως είναι ένα ψηφιακά υπογεγραμμένο JWT.

Περιλαμβάνει πεδία όπως:

  • sub: Αναγνωριστικό χρήστη.

  • iss: Εκδότης του token.

  • aud: Εφαρμογή για την οποία προορίζεται.

  • exp: Χρόνος λήξης.

  • nonce: Τιμή σύνδεσης με την αρχική διαδικασία, όταν χρησιμοποιείται.

Παράδειγμα

Η Google εκδίδει έγκυρο ID Token που προορίζεται για το example.gr.

Αν κάποιος επιχειρήσει να χρησιμοποιήσει το ίδιο token στο CodeCraft, η εφαρμογή πρέπει να το απορρίψει. Το πεδίο aud δεν αντιστοιχεί στον αναμενόμενο παραλήπτη.

Το CodeCraft πρέπει επίσης να επαληθεύει την υπογραφή, τον εκδότη, τη λήξη και τους υπόλοιπους απαιτούμενους ελέγχους.

ID Token ή Access Token;

Η διαφορά είναι ουσιαστική.

  • ID Token: Χρησιμοποιείται για να επαληθεύσουμε την ταυτοποίηση του χρήστη.

  • Access Token: Χρησιμοποιείται για να ζητήσουμε πρόσβαση σε προστατευμένα APIs.

Ένα ID Token δεν πρέπει να χρησιμοποιείται αυθαίρετα ως Access Token.

12. State και Nonce : Δύο διαφορετικές προστασίες

Στις διαδικασίες OAuth και OpenID Connect συναντάμε δύο ακόμη έννοιες.

State

Το State είναι μια τιμή που δημιουργεί η εφαρμογή όταν ξεκινά τη διαδικασία εξουσιοδότησης.

Παράδειγμα

Το CodeCraft δημιουργεί ένα τυχαίο state και το συνδέει με την τρέχουσα διαδικασία.

Η Google επιστρέφει την ίδια τιμή μαζί με την απάντηση εξουσιοδότησης. Το CodeCraft συγκρίνει την επιστρεφόμενη τιμή με εκείνη που περιμένει.

Αν διαφέρουν, το αίτημα απορρίπτεται.

Το State βοηθά να συνδέσουμε την απάντηση με το αρχικό αίτημα και μπορεί να χρησιμοποιηθεί για προστασία από CSRF.

Nonce

Το Nonce συνδέει το ID Token με μια συγκεκριμένη διαδικασία ταυτοποίησης.

Παράδειγμα

Το CodeCraft στέλνει nonce = 847291.

Το ID Token που επιστρέφει ο πάροχος πρέπει να περιλαμβάνει την αναμενόμενη τιμή, όταν αυτή έχει ζητηθεί.

Αν το Nonce είναι διαφορετικό, η εφαρμογή απορρίπτει το token.

Η διαφορά τους συνοψίζεται ως εξής:

  • State: Συσχετίζει την απάντηση εξουσιοδότησης με το αίτημα της εφαρμογής.

  • Nonce: Συσχετίζει το ID Token με την αναμενόμενη διαδικασία ταυτοποίησης.

  • PKCE: Προστατεύει την ανταλλαγή του Authorization Code.

Οι τρεις μηχανισμοί δεν είναι απλώς διαφορετικές ονομασίες για το ίδιο πράγμα. Καλύπτουν διαφορετικούς κινδύνους, αν και ορισμένες προστασίες τους μπορεί να αλληλεπικαλύπτονται.

Συμπέρασμα : Από την ταυτότητα στην ασφαλή πρόσβαση

Η ασφάλεια μιας σύγχρονης εφαρμογής δεν σταματά στην επαλήθευση ενός password.

Χρειάζεται να γνωρίζουμε ποιος συνδέεται, ποια δικαιώματα διαθέτει και πώς προστατεύονται τα στοιχεία πρόσβασης. Πρέπει επίσης να μπορούμε να περιορίζουμε, να ανανεώνουμε και να ανακαλούμε αυτά τα δικαιώματα όταν απαιτείται.

Τα Passkeys και οι ψηφιακές υπογραφές αξιοποιούν την ασύμμετρη κρυπτογραφία για την επαλήθευση κατοχής κλειδιών. Τα JWT μεταφέρουν ελεγχόμενους ισχυρισμούς, ενώ το OAuth 2.0 και το OpenID Connect οργανώνουν την εξουσιοδότηση και την ταυτοποίηση μεταξύ συστημάτων.

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

Τι ακολουθεί στο Part 3;

Στο επόμενο μέρος θα εξετάσουμε τη διαχείριση κρυπτογραφικών κλειδιών, το Key Rotation, τα Security Logs και το Monitoring.

Θα δούμε επίσης πώς μια εφαρμογή εντοπίζει ύποπτη δραστηριότητα και πώς οργανώνεται η αντιμετώπιση ενός περιστατικού ασφαλείας.


Πηγές και περαιτέρω ανάγνωση

Πώς σου φάνηκε;

Δημοσιογραφική Ομάδα CodeCraft.gr

Η συντακτική ομάδα του CodeCraft καλύπτει τεχνολογία, AI, hardware και software.

Σχόλια

Φόρτωση σχολίων…