spinny:~/writing $ vim passkeys-webauthn-passwordless-authentication.md
1~2Kata 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.3~4passkey tidak membuat autentikasi menjadi sempurna, tetapi menghilangkan masalah besar: server tidak lagi harus menyimpan rahasia yang dibagikan kepada pengguna.5~6## Apa yang sebenarnya terjadi7~8passkey adalah kredensial berdasarkan WebAuthn. Saat pengguna membuatnya, perangkat menghasilkan pasangan kunci:9~10- kunci pribadi, yang tetap ada di perangkat atau di pengelola kata sandi;11- kunci publik, yang dapat disimpan oleh server.12~13Saat masuk, server tidak meminta "beri tahu saya kata sandinya". Kirim tantangan acak. Perangkat menandatanganinya dengan kunci pribadi. Server memverifikasi tanda tangan dengan kunci publik.14~15Itu 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.16~17## Browser bertindak sebagai jembatan18~19Di browser, dua API utama adalah:20~21- `navigator.credentials.create()` untuk membuat passkey;22- `navigator.credentials.get()` untuk menggunakannya saat login.23~24Tapi logika yang penting ada di server. Server harus membuat tantangan, menyimpannya sementara, memverifikasi respons, memeriksa sumber dan Relying Party ID, lalu membuat sesi.25~26Bagian klien seharusnya hampir membosankan:27~28```typescript29const options = await fetch('/api/passkeys/login/options').then((r) => r.json());30~31const credential = await navigator.credentials.get({32 publicKey: PublicKeyCredential.parseRequestOptionsFromJSON(options),33});34~35await fetch('/api/passkeys/login/verify', {36 method: 'POST',37 headers: { 'Content-Type': 'application/json' },38 body: JSON.stringify(credential?.toJSON()),39});40```41~42Jika Anda menerapkan enkripsi WebAuthn secara manual, hentikan. Gunakan perpustakaan sisi server yang kuat. Kesalahan di sini bukanlah "bug lucu", melainkan lubang otentikasi.43~44## Apa yang harus disimpan dalam database45~46Tidak perlu menyelamatkan separuh dunia. Biasanya cukup:47~48- ID kredensial;49- kunci publik;50- pengguna yang terhubung;51- penghitung verifikasi atau metadata apa pun;52- transportasi, jika berguna untuk UX;53- nama yang dipilih oleh pengguna;54- tanggal pembuatan dan penggunaan terakhir.55~56Tabel minimal mungkin terlihat seperti ini:57~58```sql59create table passkey_credentials (60 id uuid primary key default gen_random_uuid(),61 user_id uuid not null references users(id),62 credential_id text not null unique,63 public_key text not null,64 name text,65 created_at timestamptz not null default now(),66 last_used_at timestamptz67);68```69~70Lalu saya akan menambahkan log audit dan pemberitahuan: jika seseorang membuat passkey baru di akun saya, saya ingin mengetahuinya.71~72## UX lebih penting daripada demo73~74Demo passkey selalu indah: Anda mengeklik, Face ID, Anda ikut serta. Produk sebenarnya lebih rumit.75~76Seseorang mengganti teleponnya. Seseorang menggunakan komputer perusahaan yang terkunci. Beberapa orang tidak mengerti mengapa browser menyarankan passkey. Seseorang kehilangan akses ke perangkatnya.77~78Inilah sebabnya saya tidak akan memulai dengan "mulai hari ini tidak ada lagi kata sandi untuk semua orang". Saya akan memulai seperti ini:79~801. passkey opsional untuk pengguna internal;812. saran untuk membuatnya setelah login berhasil;823. halaman akun untuk mengganti nama dan menghapus passkey;834. hapus mundur;845. peluncuran bertahap di login utama.85~86Teks di antarmuka harus sederhana. "Gunakan layar kunci perangkat Anda" lebih baik daripada "otentikasi dengan kredensial FIDO2 penduduk".87~88## Kesalahan yang ingin saya hindari89~90Jangan menimbulkan tantangan pada klien. Tantangan dibuat di server dan harus diverifikasi hanya sekali.91~92Jangan hanya mempercayai ID kredensial. Anda perlu memverifikasi tanda tangan, tantangan, asal, dan Relying Party ID.93~94Jangan hapus fallback sebelum Anda memiliki alur pemulihan yang baik. Tanpa kata sandi tidak harus berarti "jika Anda kehilangan ponsel, Anda akan keluar selamanya".95~96Jangan perlakukan passkey hanya sebagai tombol frontend. Menyembunyikan tombol bukanlah keamanan: verifikasi sebenarnya dilakukan di sisi server.97~98## Passkey-pertama atau passkey-ramah?99~100Untuk 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.101~102Migrasi yang ideal tidak terasa. Pengguna menemukan bahwa login lebih mudah, bukan karena perusahaan telah mengubah protokol otentikasinya.103~104## Kesimpulan105~106passkey 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.107~108Namun 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.109~110## Sumber111~112- [MDN: Passkeys](https://developer.mozilla.org/en-US/docs/Web/Security/Authentication/Passkeys)113- [MDN: Web Authentication API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API)114- [W3C: Web Authentication](https://www.w3.org/TR/webauthn-3/)115- [passkeys.dev](https://passkeys.dev/)116~
NORMAL · passkeys-webauthn-passwordless-authentication.md [readonly]116 lines · :q to close