Kata sandi adalah salah satu hal yang telah kami normalkan hanya karena kami telah menggunakannya selama bertahun-tahun. Pengguna melupakannya, menggunakannya kembali, menulisnya di tempat yang tidak seharusnya. Tim harus mengelola pengaturan ulang, kebijakan, hash, kebocoran, phishing, dan dukungan.
passkey tidak membuat autentikasi menjadi sempurna, tetapi menghilangkan masalah besar: server tidak lagi harus menyimpan rahasia yang dibagikan kepada pengguna.
Apa yang sebenarnya terjadi
passkey adalah kredensial berdasarkan WebAuthn. Saat pengguna membuatnya, perangkat menghasilkan pasangan kunci:
- kunci pribadi, yang tetap ada di perangkat atau di pengelola kata sandi;
- kunci publik, yang dapat disimpan oleh server.
Saat masuk, server tidak meminta "beri tahu saya kata sandinya". Kirim tantangan acak. Perangkat menandatanganinya dengan kunci pribadi. Server memverifikasi tanda tangan dengan kunci publik.
Itu bagian yang menyenangkan: jika database dicuri, tidak ada kata sandi di dalamnya yang bisa dipecahkan. Dan jika pengguna berakhir di domain palsu, passkey tidak valid untuk domain tersebut. Bukan hanya kenyamanan, tapi juga perlindungan nyata terhadap phishing.
Browser bertindak sebagai jembatan
Di browser, dua API utama adalah:
navigator.credentials.create()untuk membuat passkey;navigator.credentials.get()untuk menggunakannya saat login.
Tapi logika yang penting ada di server. Server harus membuat tantangan, menyimpannya sementara, memverifikasi respons, memeriksa sumber dan Relying Party ID, lalu membuat sesi.
Bagian klien seharusnya hampir membosankan:
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()), });
Jika Anda menerapkan enkripsi WebAuthn secara manual, hentikan. Gunakan perpustakaan sisi server yang kuat. Kesalahan di sini bukanlah "bug lucu", melainkan lubang otentikasi.
Apa yang harus disimpan dalam database
Tidak perlu menyelamatkan separuh dunia. Biasanya cukup:
- ID kredensial;
- kunci publik;
- pengguna yang terhubung;
- penghitung verifikasi atau metadata apa pun;
- transportasi, jika berguna untuk UX;
- nama yang dipilih oleh pengguna;
- tanggal pembuatan dan penggunaan terakhir.
Tabel minimal mungkin terlihat seperti ini:
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 );
Lalu saya akan menambahkan log audit dan pemberitahuan: jika seseorang membuat passkey baru di akun saya, saya ingin mengetahuinya.
UX lebih penting daripada demo
Demo passkey selalu indah: Anda mengeklik, Face ID, Anda ikut serta. Produk sebenarnya lebih rumit.
Seseorang mengganti teleponnya. Seseorang menggunakan komputer perusahaan yang terkunci. Beberapa orang tidak mengerti mengapa browser menyarankan passkey. Seseorang kehilangan akses ke perangkatnya.
Inilah sebabnya saya tidak akan memulai dengan "mulai hari ini tidak ada lagi kata sandi untuk semua orang". Saya akan memulai seperti ini:
- passkey opsional untuk pengguna internal;
- saran untuk membuatnya setelah login berhasil;
- halaman akun untuk mengganti nama dan menghapus passkey;
- hapus mundur;
- peluncuran bertahap di login utama.
Teks di antarmuka harus sederhana. "Gunakan layar kunci perangkat Anda" lebih baik daripada "otentikasi dengan kredensial FIDO2 penduduk".
Kesalahan yang ingin saya hindari
Jangan menimbulkan tantangan pada klien. Tantangan dibuat di server dan harus diverifikasi hanya sekali.
Jangan hanya mempercayai ID kredensial. Anda perlu memverifikasi tanda tangan, tantangan, asal, dan Relying Party ID.
Jangan hapus fallback sebelum Anda memiliki alur pemulihan yang baik. Tanpa kata sandi tidak harus berarti "jika Anda kehilangan ponsel, Anda akan keluar selamanya".
Jangan perlakukan passkey hanya sebagai tombol frontend. Menyembunyikan tombol bukanlah keamanan: verifikasi sebenarnya dilakukan di sisi server.
Passkey-pertama atau passkey-ramah?
Untuk produk baru Anda bisa berpikir passkey-pertama. Untuk aplikasi yang sudah ada, saya lebih suka ramah passkey: tambahkan passkey sebagai metode yang direkomendasikan, ukur keberhasilan dan masalah, lalu dengan tenang kurangi bobot kata sandi.
Migrasi yang ideal tidak terasa. Pengguna menemukan bahwa login lebih mudah, bukan karena perusahaan telah mengubah protokol otentikasinya.
Kesimpulan
passkey menarik karena meningkatkan keamanan dan UX secara bersamaan, dan hal ini jarang terjadi. Ini bukanlah sebuah tongkat ajaib: pemulihan, kompatibilitas, dukungan, dan peluncuran masih harus dirancang dengan baik.
Namun perubahan mendasarnya kuat. Berhenti meminta pengguna untuk menciptakan dan melindungi rahasia. Anda membiarkan perangkat menandatangani bukti kriptografi yang terkait dengan domain Anda. Lebih sedikit memori manusia, lebih sedikit phishing, lebih sedikit pengaturan ulang kata sandi. Menurut saya, hal-hal tersebut layak untuk ditanggapi dengan serius.