Topik wawancara representatif

Wawancara Frontend: Bagaimana Anda Akan Merancang Login Passkey yang Aman dan Dapat Dipulihkan?

FrontendSulit
Tim Redaksi Offer.ccDipublikasikan Diperbarui

Pertanyaan

Anda perlu menambahkan login Passkey ke sebuah situs web. Bagaimana Anda akan merancang pendaftaran, proses masuk, autofill kondisional, peramban yang tidak didukung, dan pemulihan setelah pengguna kehilangan perangkat?

Perintah dan cakupan

Anda memiliki situs web yang sudah memiliki login kata sandi dan ingin menambahkan Passkey. Pada peramban yang didukung, pengguna harus mengautentikasi dengan pembuka kunci platform atau kunci keamanan sambil mempertahankan jalur fallback dan pemulihan yang mudah dipahami. Rancang kolaborasi frontend dan server, termasuk navigator.credentials.create(), navigator.credentials.get(), challenge, RP ID, pemeriksaan origin, dan batasan siklus hidup kredensial.

WebAuthn adalah API autentikasi kunci publik antara peramban dan autentikator. Kunci privat tetap berada di autentikator dan situs web menyimpan kunci publik. Frontend memperoleh opsi server, memanggil API peramban, membuat serialisasi hasil, dan merender status; server harus memverifikasi tanda tangan, mengonsumsi challenge, dan mengikat kredensial ke akun.

Apa yang sedang diuji oleh pewawancara

Jawaban yang kuat memisahkan pendaftaran dan proses masuk menjadi dua alur stateful yang singkat: server membuat challenge satu kali yang tidak dapat diprediksi, frontend memanggil autentikator, dan server memverifikasi challenge yang dikembalikan, origin, RP ID, tanda tangan, dan penghitung (counter) sebelum membuat sesi. Ini juga mencakup konteks aman HTTPS, pembatalan oleh pengguna, batas waktu (timeout), migrasi perangkat, beberapa kredensial, dan pemulihan alih-alih menganggap "Face ID muncul" sebagai keberhasilan protokol.

Pewawancara akan memperhatikan apakah Anda memahami bahwa autofill kondisional adalah kemampuan UX, bukan pengganti verifikasi server. Mereka mungkin juga menanyakan mengapa penghapusan kredensial server harus diikuti oleh API sinyal WebAuthn sehingga autentikator dapat memperbarui statusnya.

Pertanyaan untuk diklarifikasi terlebih dahulu

Klien yang didukung dan kebijakan akun

Konfirmasikan peramban target, platform seluler dan desktop, apakah kredensial yang dapat ditemukan (discoverable credentials) yang disinkronkan diizinkan, dan apakah kata sandi atau kunci keamanan tetap tersedia. Pilihan-pilihan tersebut memengaruhi residentKey, userVerification, pemilihan kredensial, dan teks bantuan.

Domain dan topologi deployment

Konfirmasikan subdomain produksi dan login, iframe, reverse proxy, dan domain khusus tenant. RP ID harus merupakan domain terkait yang valid untuk origin saat ini. Domain pratinjau yang berpindah ke produksi tidak dapat menggunakan kembali konfigurasi secara aman hanya berdasarkan asumsi.

Pemulihan dan tindakan berisiko tinggi

Tanyakan bagaimana pengguna membuktikan kepemilikan saat setiap autentikator hilang, dan apakah pengaturan ulang mencabut sesi, memberi tahu pengguna, atau menunda tindakan berisiko tinggi. Pemulihan adalah bagian dari siklus hidup identitas; ini tidak dapat direduksi menjadi tautan frontend "gunakan kata sandi".

Kerangka jawaban 30 detik

"Baik pendaftaran maupun proses masuk dimulai dengan challenge satu kali yang tidak dapat diprediksi dari server. Frontend meneruskan opsi ke WebAuthn. Selama pendaftaran, server memverifikasi challenge, origin, RP ID, kebijakan atestasi, dan kunci publik sebelum mengikat ID kredensial ke akun. Selama proses masuk, server memverifikasi tanda tangan asersi, challenge, RP ID, origin, dan penghitung tanda tangan sebelum membuat sesi. Frontend membedakan status tidak didukung, dibatalkan, waktu habis, dan ditolak. Mediasi kondisional dapat menyediakan autofill tetapi tidak diwajibkan untuk kebenaran protokol. Kehilangan perangkat melewati pemulihan yang dikontrol risiko, mencabut sesi lama, dan memungkinkan kredensial baru didaftarkan."

Solusi langkah demi langkah

Langkah 1: Biarkan server membuat challenge

Halaman pendaftaran atau proses masuk pertama-tama meminta server untuk membuat alur. Server menghasilkan setidaknya 16 byte data challenge acak dan menyimpan hash, akun, tujuan, masa berlaku, dan status konsumsinya. Frontend tidak boleh membuat atau menggunakannya kembali: jika tidak, asersi lama dapat dipindahkan ke alur lain. Server mengembalikan opsi publicKey untuk RP saat ini, dan frontend tidak menulis ulang bidang yang sensitif terhadap keamanan.

Langkah 2: Rancang pendaftaran

Dalam konteks aman HTTPS, frontend memanggil navigator.credentials.create(). Opsi mencakup RP, ID pengguna, nama tampilan, algoritma kunci publik yang diterima, preferensi verifikasi pengguna, dan kebijakan kredensial yang dapat ditemukan. Setelah Promise diselesaikan, frontend membuat serialisasi ID kredensial, data klien, respons atestasi, dan ekstensi yang diperlukan ke server. Kunci privat tidak pernah meninggalkan autentikator.

Langkah 3: Verifikasi pendaftaran di server

Server memeriksa bahwa challenge cocok dengan alur, origin diizinkan, hash RP ID benar, serta tanda tangan dan algoritma kunci publik memenuhi kebijakan. Server memutuskan apakah akan memvalidasi atestasi berdasarkan tujuan privasi dan kompatibilitas. Jika berhasil, server hanya menyimpan kunci publik, ID kredensial, akun, penghitung tanda tangan, dan label perangkat yang diperlukan. Server tidak boleh menyimpan seluruh objek mentah atau data perangkat yang dapat diidentifikasi selamanya.

Langkah 4: Rancang proses masuk dan autofill kondisional

Untuk proses masuk, server membuat challenge baru dan frontend memanggil navigator.credentials.get() dengannya, lalu mengirimkan asersi. Server memverifikasi challenge, origin, RP ID, tanda tangan, dan penghitung sebelum menyelesaikan akun dari ID kredensial. Dengan mediasi kondisional, halaman dapat meminta kredensial yang dapat ditemukan setelah pengguna berinteraksi dengan kolom nama pengguna, memungkinkan peramban menampilkan Passkey di autofill. Ini mengubah UX penemuan, bukan kontrak verifikasi.

Langkah 5: Tangani status frontend dan kegagalan

Pembatalan, batas waktu habis, peramban yang tidak didukung, kebijakan izin yang diblokir, dan penolakan server harus menjadi status yang berbeda dan dapat dipahami pengguna. AbortController dapat membatalkan panggilan yang tertunda saat pengguna keluar atau mengklik lagi, mencegah Promise lama menimpa status saat ini. Frontend tidak boleh menampilkan tanda tangan, ID kredensial, atau kesalahan internal server, dan tidak boleh menandai pendaftaran yang tidak lengkap sebagai berhasil.

Langkah 6: Pemulihan, pencabutan, dan pengelolaan kredensial

Pengaturan akun harus mencantumkan label kredensial, waktu pembuatan, dan waktu terakhir digunakan, serta memungkinkan satu kredensial dihapus. Setelah server menghapusnya, ID kredensial yang tidak dikenal di kemudian hari dapat memicu PublicKeyCredential.signalUnknownCredential(); proses masuk yang berhasil dapat menggunakan signalAllAcceptedCredentials() untuk menyinkronkan ID yang masih diterima oleh server. Kehilangan setiap autentikator menggunakan pemulihan yang dikontrol risiko seperti kata sandi ditambah pemeriksaan risiko, email yang diverifikasi, atau tinjauan dukungan. Cabut sesi lama lalu wajibkan pendaftaran Passkey baru.

Langkah 7: Verifikasi dan kembangkan

Uji berbagai peramban, autentikator platform, kredensial yang disinkronkan, kunci keamanan, pembatalan, batas waktu habis, origin yang salah, challenge yang kedaluwarsa dan berulang, anomali penghitung, dan kredensial lama pascapemulihan. Deteksi kapabilitas dan terima kebijakan dari server alih-alih menebak dari string user-agent. Ekstensi baru harus bersifat opsional dengan UI fallback, dan ekstensi yang tidak dikenal tidak boleh mengubah verifikasi inti server.

Contoh jawaban berkualitas tinggi

Saya akan memperlakukan Passkey sebagai alur autentikasi kunci publik yang digerakkan oleh server. Saat pengguna memulai pendaftaran, frontend meminta challenge satu kali dan opsi publicKey dari server, lalu memanggil WebAuthn melalui HTTPS. Server saja yang memverifikasi challenge, origin, RP ID, tanda tangan, algoritma, dan atestasi apa pun yang diperlukan, lalu menyimpan ID kredensial, kunci publik, penghitung, dan pengikatan akun. Kunci privat tetap berada di dalam autentikator.

Proses masuk dimulai dengan challenge server lainnya. Frontend memanggil navigator.credentials.get(), mengirimkan asersi, dan server memverifikasi tanda tangan, challenge, origin, RP ID, dan penghitungnya sebelum membuat sesi. Jika mediasi kondisional didukung, saya menawarkan autofill Passkey setelah interaksi pada kolom nama pengguna, tetapi tetap mengikuti verifikasi server yang sama.

Frontend membedakan status tidak didukung, dibatalkan, batas waktu habis, dan ditolak, serta membatalkan panggilan tertunda saat halaman ditinggalkan. Pengaturan akun mencantumkan dan menghapus kredensial; setelah penghapusan, sinyal WebAuthn mencegah peramban menyarankan kredensial yang tidak dikenal. Kehilangan perangkat memerlukan pemulihan yang dikontrol risiko, mencabut sesi lama, memberi tahu pengguna, dan mendaftarkan kredensial pengganti. Pengujian mencakup autentikator lintas platform, origin yang salah, challenge kedaluwarsa atau berulang, anomali penghitung, fallback peramban, dan kredensial lama setelah pemulihan sehingga perubahan UX tidak pernah melemahkan verifikasi protokol.

Kesalahan umum

  • Kesalahan: Menghasilkan challenge di frontend atau meletakkannya di konstanta halaman. → Mengapa ini gagal: Penyerang dapat memutar ulang (replay) asersi lama dan server tidak dapat memastikan kebaruan (freshness) alur. → Perbaikan: Hasilkan di server, simpan sebentar, konsumsi sekali, dan ikat ke akun serta tujuannya.
  • Kesalahan: Memasukkan pengguna (sign in) saat Promise selesai. → Mengapa ini gagal: Objek peramban bukanlah bukti bahwa server telah memverifikasi origin, RP ID, dan tanda tangan. → Perbaikan: Selesaikan validasi asersi di server dan biarkan frontend merender hasil terstruktur.
  • Kesalahan: Mendeteksi dukungan dengan string user-agent. → Mengapa ini gagal: Versi peramban, autentikator platform, dan kebijakan izin bervariasi. → Perbaikan: Gunakan API kapabilitas dan kebijakan server, lalu berikan rute kata sandi atau kunci keamanan yang eksplisit.
  • Kesalahan: Menghapus kredensial basis data tanpa menyinkronkan status perangkat. → Mengapa ini gagal: Autentikator masih mengira kredensial itu ada dan terus menawarkan opsi yang tidak dapat digunakan. → Perbaikan: Panggil API sinyal WebAuthn dalam status terautentikasi yang sesuai dan sediakan jalur pendaftaran ulang.

Pertanyaan lanjutan dan tanggapan

Pertanyaan lanjutan 1: Mengapa RP ID tidak bisa berupa domain API apa pun?

RP ID harus berupa domain yang terkait dengan origin saat ini dan diperiksa oleh peramban dan server. Nilai yang tidak terkait membuat pembuatan gagal atau memperluas cakupan kepercayaan. Untuk domain multi-tenant, konfigurasikan setiap domain tepercaya secara eksplisit; jangan pernah menerima string arbitrer yang disediakan klien.

Pertanyaan lanjutan 2: Pengguna mendaftar di ponsel, tetapi desktop tidak memiliki kunci. Bagaimana sekarang?

Jika kredensial yang dapat ditemukan dan disinkronkan diizinkan, peramban dan pengelola kredensial dapat menyediakan Passkey akun yang sama di seluruh perangkat. Jika tidak, tawarkan alur QR lintas perangkat atau kunci keamanan. Frontend harus menyatakan bahwa perangkat tidak dapat menggunakan kredensial dan memberikan tindakan; server tetap memverifikasi aturan challenge dan asersi yang sama, termasuk origin.

Pertanyaan lanjutan 3: Haruskah pemutaran balik penghitung (counter rollback) langsung mengunci akun?

Pertama-tama bedakan antara kredensial platform yang disinkronkan, pemulihan cadangan, dan risiko kloning asli. Perlakukan anomali sebagai sinyal risiko yang mungkin memerlukan verifikasi ekstra dan memberi tahu pengguna, daripada mengunci secara permanen tanpa konteks. Tindakan bernilai tinggi dapat memerlukan kredensial terdaftar lainnya atau tinjauan dukungan, dengan keputusan yang dicatat untuk penyesuaian kebijakan.

Pertanyaan lanjutan 4: Apakah pemulihan melemahkan keamanan Passkey?

Ya, jika pemulihan hanya mengandalkan tautan email yang berpotensi disusupi. Gunakan pemeriksaan risiko berjenjang, pencabutan sesi, masa tenang (cooling period), pemberitahuan, dan penundaan tindakan berisiko tinggi. Setelah pemulihan, daftarkan kredensial baru dan hapus yang lama. Jelaskan trade-off antara ketersediaan versus pengambilalihan akun (account takeover) alih-alih menjanjikan bahwa pengguna tidak akan pernah kehilangan akses.

Sumber publik

Pertanyaan terkait