Login dengan kunci sandi melalui isi otomatis formulir

Buat pengalaman login yang memanfaatkan kunci sandi sekaligus tetap mengakomodasi pengguna sandi yang ada.

Kunci sandi menggantikan sandi dan membuat akun pengguna di web menjadi lebih aman, lebih sederhana, dan lebih mudah digunakan. Namun, transisi dari autentikasi berbasis sandi ke autentikasi berbasis kunci sandi dapat mempersulit pengalaman pengguna. Menggunakan isi otomatis formulir untuk menyarankan kunci sandi dapat membantu membuat pengalaman terpadu.

Dengan kunci sandi, pengguna dapat login ke situs hanya dengan menggunakan sidik jari, wajah, atau PIN perangkat.

Idealnya, tidak akan ada pengguna sandi dan alur autentikasi dapat semudah tombol login sekali. Saat pengguna mengetuk tombol, dialog pemilih akun akan muncul, pengguna dapat memilih akun, membuka kunci layar untuk memverifikasi dan login.

Namun, peralihan dari autentikasi berbasis sandi ke autentikasi berbasis kunci sandi dapat menjadi tantangan. Saat pengguna beralih ke kunci sandi, masih akan ada pengguna yang menggunakan sandi dan situs harus mengakomodasi kedua jenis pengguna tersebut. Pengguna sendiri tidak diharapkan untuk mengingat situs mana yang telah mereka alihkan ke kunci sandi, jadi meminta pengguna untuk memilih metode yang akan digunakan di awal akan menjadi UX yang buruk.

Kunci sandi juga merupakan teknologi baru. Menjelaskannya dan memastikan pengguna merasa nyaman menggunakannya dapat menjadi tantangan bagi situs. Kita dapat mengandalkan pengalaman pengguna yang sudah dikenal untuk mengisi otomatis sandi guna mengatasi kedua masalah tersebut.

UI Bersyarat

Untuk membuat pengalaman pengguna yang efisien bagi pengguna kunci sandi dan sandi, Anda dapat menyertakan kunci sandi dalam saran isi otomatis. Ini disebut UI kondisional dan merupakan bagian dari standar WebAuthn.

Segera setelah pengguna mengetuk kolom input nama pengguna, dialog saran isi otomatis akan muncul yang menandai kunci sandi yang disimpan beserta saran isi otomatis sandi. Kemudian, pengguna dapat memilih akun dan menggunakan kunci layar perangkat untuk login.

Dengan cara ini, pengguna dapat login ke situs Anda dengan formulir yang ada seolah-olah tidak ada yang berubah, tetapi dengan manfaat keamanan tambahan dari kunci sandi jika mereka memilikinya.

Cara kerjanya

Untuk mengautentikasi dengan kunci sandi, Anda menggunakan WebAuthn API.

Empat komponen dalam alur autentikasi kunci sandi adalah: pengguna:

  • Backend: Server backend Anda yang menyimpan database akun yang menyimpan kunci publik dan metadata lainnya tentang kunci sandi.
  • Frontend: Frontend Anda yang berkomunikasi dengan browser dan mengirim permintaan pengambilan ke backend.
  • Browser: Browser pengguna yang menjalankan JavaScript Anda.
  • Authenticator: Pengautentikasi pengguna yang membuat dan menyimpan kunci sandi. Ini mungkin di perangkat yang sama dengan browser (misalnya, saat menggunakan Windows Hello) atau di perangkat lain, seperti ponsel.
Diagram autentikasi kunci sandi
  1. Segera setelah pengguna membuka frontend, frontend akan meminta verifikasi dari backend untuk mengautentikasi dengan kunci sandi dan memanggil navigator.credentials.get() untuk memulai autentikasi dengan kunci sandi. Tindakan ini akan menampilkan Promise.
  2. Saat pengguna menempatkan kursor di kolom login, browser akan menampilkan dialog isi otomatis sandi termasuk kunci sandi. Dialog autentikasi akan muncul jika pengguna memilih kunci sandi.
  3. Setelah pengguna memverifikasi identitasnya menggunakan kunci layar perangkat, promise akan di-resolve dan kredensial kunci publik akan ditampilkan ke frontend.
  4. Frontend mengirim kredensial kunci publik ke backend. Backend memverifikasi tanda tangan dengan kunci publik akun yang cocok di database. Jika berhasil, pengguna akan login.

Mengautentikasi dengan kunci sandi melalui isi otomatis formulir

Saat pengguna ingin login, Anda dapat melakukan panggilan get WebAuthn kondisional untuk menunjukkan bahwa kunci sandi dapat disertakan dalam saran isi otomatis. Panggilan bersyarat ke navigator.credentials.get() API WebAuthn tidak menampilkan UI dan tetap tertunda hingga pengguna memilih akun untuk login dari saran isi otomatis. Jika pengguna memilih kunci sandi, browser akan me-resolve promise dengan kredensial, bukan mengisi formulir login. Kemudian, halaman tersebut bertanggung jawab untuk membuat pengguna login.

Menganotasi kolom input formulir

Tambahkan atribut autocomplete ke kolom input nama pengguna, jika diperlukan. Tambahkan username dan webauthn sebagai tokennya agar dapat menyarankan kunci sandi.

<input type="text" name="username" autocomplete="username webauthn" ...>

Deteksi fitur

Sebelum memanggil panggilan API WebAuthn kondisional, periksa apakah:

  • Browser mendukung WebAuthn dengan PublicKeyCredential.

Dukungan Browser

  • Chrome: 67.
  • Edge: 18.
  • Firefox: 60.
  • Safari: 13.

Sumber

Dukungan Browser

  • Chrome: 108.
  • Edge: 108.
  • Firefox: 119.
  • Safari: 16.

Sumber

// Availability of `window.PublicKeyCredential` means WebAuthn is usable.  
if (window.PublicKeyCredential &&  
   
PublicKeyCredential.​​isConditionalMediationAvailable) {  
 
// Check if conditional mediation is available.  
 
const isCMA = await PublicKeyCredential.​​isConditionalMediationAvailable();  
 
if (isCMA) {  
   
// Call WebAuthn authentication  
 
}  
}  

Mengambil verifikasi login dari server RP

Ambil tantangan dari server RP yang diperlukan untuk memanggil navigator.credentials.get():

  • challenge: Tantangan yang dibuat server di ArrayBuffer. Hal ini diperlukan untuk mencegah serangan replay. Pastikan untuk membuat tantangan baru pada setiap upaya login dan mengabaikannya setelah durasi tertentu atau setelah upaya login gagal divalidasi. Anggap saja seperti token CSRF.
  • allowCredentials: Array kredensial yang dapat diterima untuk autentikasi ini. Teruskan array kosong agar pengguna dapat memilih kunci sandi yang tersedia dari daftar yang ditampilkan oleh browser.
  • userVerification: Menunjukkan apakah verifikasi pengguna yang menggunakan kunci layar perangkat adalah "required", "preferred", atau "discouraged". Setelan defaultnya adalah "preferred", yang berarti pengautentikasi dapat melewati verifikasi pengguna. Tetapkan ini ke "preferred" atau hapus properti.

Memanggil WebAuthn API dengan tanda conditional untuk mengautentikasi pengguna

Panggil navigator.credentials.get() untuk mulai menunggu autentikasi pengguna.

// To abort a WebAuthn call, instantiate an `AbortController`.
const abortController = new AbortController();

const publicKeyCredentialRequestOptions = {
 
// Server generated challenge
  challenge
: ****,
 
// The same RP ID as used during registration
  rpId
: 'example.com',
};

const credential = await navigator.credentials.get({
  publicKey
: publicKeyCredentialRequestOptions,
  signal
: abortController.signal,
 
// Specify 'conditional' to activate conditional UI
  mediation
: 'conditional'
});
  • rpId: ID RP adalah domain dan situs dapat menentukan domain atau akhiran yang dapat didaftarkan. Nilai ini harus cocok dengan rp.id yang digunakan saat kunci sandi dibuat.

Jangan lupa untuk menentukan mediation: 'conditional' agar permintaan bersifat kondisional.

Mengirim kredensial kunci publik yang ditampilkan ke server RP

Setelah pengguna memilih akun dan mengizinkan penggunaan kunci layar perangkat, promise akan di-resolve dan menampilkan objek PublicKeyCredential ke frontend RP.

Promise dapat ditolak karena beberapa alasan. Anda harus menangani error dengan semestinya, bergantung pada properti name objek Error:

  • NotAllowedError: Pengguna telah membatalkan operasi.
  • Pengecualian lainnya: Terjadi error yang tidak terduga. Browser menampilkan dialog error kepada pengguna.

Objek kredensial kunci publik berisi properti berikut:

  • id: ID yang dienkode base64url dari kredensial kunci sandi yang diautentikasi.
  • rawId: Versi ArrayBuffer dari ID kredensial.
  • response.clientDataJSON: ArrayBuffer data klien. Kolom ini berisi informasi seperti verifikasi login dan asal yang perlu diverifikasi oleh server RP.
  • response.authenticatorData: ArrayBuffer data pengautentikasi. Kolom ini berisi informasi seperti ID RP.
  • response.signature: ArrayBuffer tanda tangan. Nilai ini adalah inti kredensial dan perlu diverifikasi di server.
  • response.userHandle: ArrayBuffer yang berisi ID pengguna yang ditetapkan pada waktu pembuatan. Nilai ini dapat digunakan, bukan ID kredensial, jika server perlu memilih nilai ID yang digunakannya, atau jika backend ingin menghindari pembuatan indeks pada ID kredensial.
  • authenticatorAttachment: Menampilkan platform jika kredensial ini berasal dari perangkat lokal. Jika tidak, cross-platform, terutama saat pengguna menggunakan ponsel untuk login. Jika pengguna perlu menggunakan ponsel untuk login, pertimbangkan untuk meminta mereka membuat kunci sandi di perangkat lokal.
  • type: Kolom ini selalu ditetapkan ke "public-key".

Jika Anda menggunakan library untuk menangani objek kredensial kunci publik di server RP, sebaiknya kirim seluruh objek ke server setelah mengenkodenya sebagian dengan base64url.

Memverifikasi tanda tangan

Saat Anda menerima kredensial kunci publik di server, teruskan ke library FIDO untuk memproses objek.

Cari ID kredensial yang cocok dengan properti id (Jika Anda perlu menentukan akun pengguna, gunakan properti userHandle yang merupakan user.id yang Anda tentukan saat membuat kredensial). Lihat apakah signature kredensial dapat diverifikasi dengan kunci publik yang disimpan. Untuk melakukannya, sebaiknya gunakan library sisi server atau solusi, bukan menulis kode Anda sendiri. Anda dapat menemukan library open source di repositori GitHub awesome-webauth.

Setelah kredensial diverifikasi dengan kunci publik yang cocok, minta pengguna untuk login.

Ikuti petunjuk yang lebih mendetail di Autentikasi kunci sandi sisi server

Resource