Οι κωδικοί πρόσβασης είναι ένα από εκείνα τα πράγματα που έχουμε κανονικοποιήσει μόνο και μόνο επειδή ζούμε με αυτούς για χρόνια. Οι χρήστες τα ξεχνούν, τα επαναχρησιμοποιούν, τα γράφουν εκεί που δεν πρέπει. Οι ομάδες πρέπει να διαχειρίζονται επαναφορές, πολιτικές, κατακερματισμούς, διαρροές, ηλεκτρονικό ψάρεμα και υποστήριξη.
Τα passkey δεν κάνουν τον έλεγχο ταυτότητας τέλειο, αλλά αφαιρούν ένα τεράστιο πρόβλημα: ο διακομιστής δεν χρειάζεται πλέον να κρατά ένα μυστικό κοινόχρηστο με τον χρήστη.
Τι πραγματικά συμβαίνει
Το passkey είναι ένα διαπιστευτήριο που βασίζεται στο WebAuthn. Όταν ο χρήστης το δημιουργεί, η συσκευή δημιουργεί ένα ζεύγος κλειδιών:
- ένα ιδιωτικό κλειδί, το οποίο παραμένει στη συσκευή ή στη διαχείριση κωδικών πρόσβασης.
- ένα δημόσιο κλειδί, το οποίο μπορεί να αποθηκεύσει ο διακομιστής.
Όταν συνδέεστε στον διακομιστή δεν ρωτά "πες μου τον κωδικό πρόσβασης". Στείλτε μια τυχαία πρόκληση. Η συσκευή το υπογράφει με το ιδιωτικό κλειδί. Ο διακομιστής επαληθεύει την υπογραφή με το δημόσιο κλειδί.
Αυτό είναι το ωραίο μέρος: εάν κλαπεί η βάση δεδομένων, δεν υπάρχουν κωδικοί πρόσβασης μέσα για να σπάσουν. Και αν ένας χρήστης καταλήξει σε έναν ψεύτικο τομέα, το passkey δεν ισχύει για αυτόν τον τομέα. Δεν είναι απλώς ευκολία, είναι συγκεκριμένη προστασία από το phishing.
Το πρόγραμμα περιήγησης λειτουργεί ως γέφυρα
Στο πρόγραμμα περιήγησης τα δύο κύρια API είναι:
navigator.credentials.create()για να δημιουργήσετε ένα passkey.navigator.credentials.get()για να το χρησιμοποιήσετε κατά τη σύνδεση.
Αλλά η σημαντική λογική βρίσκεται στον διακομιστή. Ο διακομιστής πρέπει να δημιουργήσει την πρόκληση, να την αποθηκεύσει προσωρινά, να επαληθεύσει την απόκριση, να ελέγξει την πηγή και Relying Party ID και, στη συνέχεια, να δημιουργήσει τη συνεδρία.
Το τμήμα πελάτη πρέπει να είναι σχεδόν βαρετό:
const options = await fetch('/api/passkeys/login/options').then((r) => r.json()); const credential = await navigator.credentials.get({ publicKey: PublicKeyCredential.parseRequestOptionsFromJSON(options), }); await fetch('/api/passkeys/login/verify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(credential?.toJSON()), });
Εάν διαπιστώσετε ότι εφαρμόζετε την κρυπτογράφηση WebAuthn με το χέρι, σταματήστε. Χρησιμοποιήστε μια ισχυρή βιβλιοθήκη από την πλευρά του διακομιστή. Τα σφάλματα εδώ δεν είναι "χαριτωμένα σφάλματα", είναι τρύπες ελέγχου ταυτότητας.
Τι να αποθηκεύσετε στη βάση δεδομένων
Δεν υπάρχει λόγος να σώσουμε τον μισό κόσμο. Συνήθως αρκετά:
- Ταυτότητα του διαπιστευτηρίου
- δημόσιο κλειδί
- συνδεδεμένος χρήστης.
- τυχόν μετρητή επαλήθευσης ή μεταδεδομένα·
- μεταφορές, εάν είναι χρήσιμες για το UX.
- όνομα που επιλέγει ο χρήστης.
- ημερομηνία δημιουργίας και τελευταία χρήση.
Ένας ελάχιστος πίνακας μπορεί να μοιάζει με αυτό:
create table passkey_credentials ( id uuid primary key default gen_random_uuid(), user_id uuid not null references users(id), credential_id text not null unique, public_key text not null, name text, created_at timestamptz not null default now(), last_used_at timestamptz );
Στη συνέχεια, θα πρόσθετα αρχεία καταγραφής ελέγχου και ειδοποιήσεις: εάν κάποιος δημιουργήσει ένα νέο passkey στον λογαριασμό μου, θέλω να το μάθω.
Το UX έχει μεγαλύτερη σημασία από την επίδειξη
Το demo ενός passkey είναι πάντα όμορφο: κάνετε κλικ, Face ID, είστε μέσα. Το πραγματικό προϊόν είναι πιο περίπλοκο.
Κάποιος αλλάζει το τηλέφωνό του. Κάποιος χρησιμοποιεί έναν κλειδωμένο υπολογιστή της εταιρείας. Μερικοί άνθρωποι δεν καταλαβαίνουν γιατί το πρόγραμμα περιήγησης προτείνει ένα passkey. Κάποιος χάνει την πρόσβαση στη συσκευή του.
Αυτός είναι ο λόγος που δεν θα ξεκινούσα με το "από σήμερα δεν υπάρχουν άλλοι κωδικοί πρόσβασης για όλους". Θα ξεκινούσα ως εξής:
- passkey προαιρετικό για εσωτερικούς χρήστες.
- Πρόταση για δημιουργία μετά από επιτυχή σύνδεση.
- σελίδα λογαριασμού για μετονομασία και κατάργηση passkey.
- σαφές εναλλακτικό.
- σταδιακή διάθεση στην κύρια είσοδο.
Το κείμενο στη διεπαφή πρέπει να είναι απλό. Η "Χρήση της οθόνης κλειδώματος της συσκευής σας" είναι καλύτερη από την "επαλήθευση ταυτότητας με διαπιστευτήριο κατοίκου FIDO2".
Λάθη που θα απέφευγα
Μην δημιουργείτε προκλήσεις στον πελάτη. Η πρόκληση δημιουργείται στον διακομιστή και πρέπει να επαληθευτεί μόνο μία φορά.
Μην εμπιστεύεστε μόνο το αναγνωριστικό διαπιστευτηρίων. Πρέπει να επαληθεύσετε την υπογραφή, την πρόκληση, την προέλευση και το Relying Party ID.
Μην διαγράφετε εναλλακτικές προτού να έχετε μια καλή ροή ανάκτησης. Χωρίς κωδικό πρόσβασης δεν χρειάζεται να γίνει "αν χάσετε το τηλέφωνό σας, θα είστε για πάντα έξω".
Μην αντιμετωπίζετε το passkey ως ένα κουμπί καθαρά frontend. Η απόκρυψη ενός κουμπιού δεν είναι ασφάλεια: η πραγματική επαλήθευση είναι από την πλευρά του διακομιστή.
Passkey-πρώτος ή passkey-φιλικός;
Για ένα νέο προϊόν μπορείτε να σκεφτείτε πρώτα passkey. Για μια υπάρχουσα εφαρμογή προτιμώ φιλική προς το passkey: προσθέστε το passkey ως προτεινόμενη μέθοδο, μετρήστε την επιτυχία και τα προβλήματα και, στη συνέχεια, μειώστε ήρεμα το βάρος του κωδικού πρόσβασης.
Η ιδανική μετανάστευση δεν γίνεται αισθητή. Ο χρήστης ανακαλύπτει ότι η σύνδεση είναι ευκολότερη και όχι ότι η εταιρεία έχει αλλάξει το πρωτόκολλο ελέγχου ταυτότητας.
Συμπέρασμα
Τα passkey είναι ενδιαφέροντα γιατί βελτιώνουν την ασφάλεια και το UX ταυτόχρονα, κάτι που είναι σπάνιο. Δεν είναι ένα μαγικό ραβδί: η ανάκτηση, η συμβατότητα, η υποστήριξη και η διάθεση πρέπει να σχεδιαστούν σωστά.
Αλλά η βασική αλλαγή είναι ισχυρή. Σταματήστε να ζητάτε από τους χρήστες να εφεύρουν και να προστατεύουν μυστικά. Αφήνετε τη συσκευή να υπογράψει μια κρυπτογραφική απόδειξη που συνδέεται με τον τομέα σας. Λιγότερη ανθρώπινη μνήμη, λιγότερο phishing, λιγότερες επαναφορές κωδικών πρόσβασης. Θα έλεγα ότι αξίζει να ληφθούν σοβαρά υπόψη.