Login dengan kunci sandi melalui isi otomatis formulir

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

Panduan ini menjelaskan cara menggunakan isi otomatis formulir untuk memungkinkan pengguna login dengan kunci sandi bersama sandi. Menggunakan pengisian otomatis formulir akan menciptakan pengalaman login terpadu, yang menyederhanakan transisi dari sandi ke metode autentikasi kunci sandi yang lebih aman dan mudah digunakan.

Pelajari cara menerapkan UI bersyarat WebAuthn untuk mendukung pengguna kunci sandi dan sandi dengan hambatan minimal di formulir login yang ada.

Mengapa menggunakan isi otomatis formulir untuk login dengan kunci sandi?

Kunci sandi memungkinkan pengguna login ke situs menggunakan sidik jari, wajah, PIN perangkat mereka.

Jika semua pengguna memiliki kunci sandi, alur autentikasi dapat berupa satu tombol login. Mengetuk tombol akan memungkinkan pengguna langsung memverifikasi akun dengan kunci layar, dan login.

Namun, transisi dari sandi ke kunci sandi menimbulkan tantangan. Situs harus mendukung pengguna sandi dan kunci sandi selama periode ini. Meminta pengguna untuk mengingat situs mana yang menggunakan kunci sandi dan meminta mereka untuk memilih metode login di awal akan memberikan pengalaman pengguna yang buruk.

Kunci sandi juga merupakan teknologi baru, dan menjelaskannya dengan jelas dapat menjadi sulit. Menggunakan antarmuka isi otomatis yang sudah dikenal membantu mengatasi tantangan transisi dan kebutuhan pengguna untuk merasa familier.

Menggunakan UI kondisional

Untuk mendukung pengguna kunci sandi dan sandi secara efektif, sertakan kunci sandi dalam saran isi otomatis formulir Anda. Pendekatan ini menggunakan UI kondisional, fitur dari standar WebAuthn.

Contoh pemilihan kunci sandi melalui isi otomatis formulir.

Saat pengguna berfokus pada kolom input nama pengguna, dialog isi otomatis akan muncul, yang menyarankan kunci sandi tersimpan bersama sandi tersimpan. Pengguna dapat memilih kunci sandi atau sandi dan melanjutkan login, menggunakan kunci layar perangkat jika mereka memilih kunci sandi.

Dengan demikian, pengguna dapat login ke situs Anda dengan formulir login yang sudah ada, tetapi dengan manfaat keamanan tambahan dari kunci sandi jika mereka memilikinya.

Cara kerja autentikasi kunci sandi

Untuk mengautentikasi dengan kunci sandi, Anda menggunakan WebAuthn API.

Empat komponen dalam alur autentikasi kunci sandi adalah:

  • Backend: Menyimpan detail akun pengguna, termasuk kunci publik.
  • Frontend: Berkomunikasi dengan browser dan mengambil data yang diperlukan dari backend.
  • Browser: Menjalankan JavaScript dan berinteraksi dengan WebAuthn API.
  • Penyedia kunci sandi: Membuat dan menyimpan kunci sandi. Ini biasanya berupa pengelola sandi seperti Pengelola Sandi Google, atau kunci keamanan.
Alur autentikasi kunci sandi, yang menunjukkan interaksi antara frontend, backend, browser, dan penyedia kunci sandi.
Alur autentikasi kunci sandi lengkap.

Proses autentikasi kunci sandi mengikuti alur ini:

  1. Pengguna membuka halaman login, dan frontend meminta tantangan autentikasi dari backend.
  2. Backend membuat dan menampilkan tantangan WebAuthn yang terkait dengan akun pengguna.
  3. Frontend memanggil navigator.credentials.get() dengan tantangan untuk memulai autentikasi menggunakan browser.
  4. Browser, yang berinteraksi dengan penyedia kunci sandi, meminta pengguna untuk memilih kunci sandi (sering kali menggunakan dialog isi otomatis yang dipicu oleh memfokuskan kolom login) dan memverifikasi identitas mereka menggunakan kunci layar perangkat atau biometrik.
  5. Setelah verifikasi pengguna berhasil, penyedia kunci sandi akan menandatangani tantangan, dan browser akan menampilkan kredensial kunci publik yang dihasilkan (termasuk tanda tangan) ke frontend.
  6. Frontend mengirimkan kredensial ini ke backend.
  7. Backend memverifikasi tanda tangan kredensial dengan kunci publik yang disimpan pengguna. Jika verifikasi berhasil, backend akan memproses login pengguna.

Mengautentikasi dengan kunci sandi melalui isi otomatis formulir

Untuk memulai autentikasi kunci sandi menggunakan isi otomatis formulir, lakukan panggilan get WebAuthn bersyarat saat halaman login dimuat. Panggilan ke navigator.credentials.get() ini menyertakan opsi mediation: 'conditional'.
Permintaan kondisional ke navigator.credentials.get() API WebAuthn tidak langsung menampilkan UI. Sebagai gantinya, kolom tersebut menunggu dalam status tertunda hingga pengguna berinteraksi dengan perintah isi otomatis kolom nama pengguna. Jika pengguna memilih kunci sandi, browser akan me-resolve promise yang tertunda dengan kredensial untuk memproses login pengguna, sehingga mengabaikan pengiriman formulir tradisional. Jika pengguna memilih sandi, promise tidak akan di-resolve, dan alur login sandi standar akan berlanjut.rm. Kemudian, halaman bertanggung jawab untuk memproses login pengguna.

Menganotasi kolom input formulir

Untuk mengaktifkan isi otomatis kunci sandi, tambahkan atribut autocomplete ke kolom input nama pengguna formulir Anda. Sertakan username dan webauthn sebagai nilai yang dipisahkan spasi.

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

Menambahkan autofocus ke kolom ini akan otomatis memicu perintah isi otomatis saat memuat halaman, yang langsung menampilkan sandi dan kunci sandi yang tersedia.

Deteksi fitur

Sebelum memanggil panggilan API WebAuthn kondisional, periksa apakah:

  • Browser mendukung WebAuthn dengan PublicKeyCredential.

Browser Support

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

Source

Browser Support

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

Source

Cuplikan berikut menunjukkan cara memeriksa apakah browser mendukung fitur ini:

// 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 informasi dari backend

Backend Anda harus menyediakan beberapa opsi ke frontend untuk memulai panggilan navigator.credentials.get(). Opsi ini biasanya diambil sebagai objek JSON dari endpoint di server Anda.

Properti utama dalam objek opsi meliputi:

  • challenge: Tantangan yang dibuat server di ArrayBuffer (biasanya Base64URL yang dienkode untuk transpor JSON). Hal ini penting untuk mencegah serangan replay. Server Anda harus membuat tantangan baru untuk setiap upaya login dan harus membatalkan validasinya setelah beberapa saat atau jika upaya gagal.
  • allowCredentials: Array deskripsi kredensial. Teruskan array kosong. Tindakan ini akan meminta browser untuk mencantumkan semua kredensial untuk rpId yang ditentukan.
  • userVerification: Menentukan preferensi Anda untuk verifikasi pengguna, seperti mewajibkan kunci layar perangkat. Nilai default dan yang direkomendasikan adalah "preferred". Kemungkinan nilainya adalah:

    • "required": Verifikasi pengguna harus dilakukan oleh pengautentikasi (seperti PIN atau biometrik). Operasi akan gagal jika verifikasi tidak dapat dilakukan.
    • "preferred": Pengautentikasi mencoba verifikasi pengguna, tetapi operasi dapat berhasil tanpanya.
    • "discouraged": Pengautentikasi harus menghindari verifikasi pengguna jika memungkinkan.
  • rpId: ID pihak tepercaya Anda, biasanya domain situs Anda (seperti example.com). Nilai ini harus sama persis dengan rp.id yang digunakan saat kredensial kunci sandi dibuat.

Server Anda harus membuat objek opsi ini. Nilai ArrayBuffer (seperti challenge) harus dienkode Base64URL untuk transpor JSON. Di frontend, setelah mengurai JSON, gunakan PublicKeyCredential.parseRequestOptionsFromJSON() untuk mengonversi objek (termasuk mendekode string Base64URL) ke dalam format yang diharapkan navigator.credentials.get().

Cuplikan kode berikut menunjukkan cara mengambil dan mendekode informasi yang diperlukan untuk mengautentikasi dengan kunci sandi.

// Fetch an encoded PubicKeyCredentialRequestOptions from the server.
const _options = await fetch('/webauthn/signinRequest');

// Deserialize and decode the PublicKeyCredentialRequestOptions.
const decoded_options = JSON.parse(_options);
const options = PublicKeyCredential.parseRequestOptionsFromJSON(decoded_options);
...

Memanggil WebAuthn API dengan tanda conditional untuk mengautentikasi pengguna

Setelah Anda menyiapkan objek publicKeyCredentialRequestOptions (disebut sebagai options dalam contoh kode di bawah), panggil navigator.credentials.get() untuk memulai autentikasi kunci sandi kondisional.

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

// Invoke WebAuthn to authenticate with a passkey.
const credential = await navigator.credentials.get({
  publicKey: options,
  signal: abortController.signal,
  // Specify 'conditional' to activate conditional UI
  mediation: 'conditional'
});

Parameter utama untuk panggilan ini:

  • publicKey: Ini harus berupa objek publicKeyCredentialRequestOptions (bernama options dalam contoh) yang Anda ambil dari server dan diproses di langkah sebelumnya.
  • signal: Meneruskan sinyal AbortController (seperti abortController.signal) memungkinkan Anda membatalkan permintaan get() secara terprogram. Hal ini berguna saat Anda ingin memanggil panggilan WebAuthn lain.
  • mediation: 'conditional': Ini adalah flag penting yang membuat panggilan WebAuthn bersifat kondisional. Tindakan ini akan memberi tahu browser untuk menunggu interaksi pengguna dengan perintah isi otomatis, bukan langsung menampilkan dialog modal.

Mengirim kredensial kunci publik yang ditampilkan ke server RP

Jika pengguna memilih kunci sandi dan berhasil memverifikasi identitasnya (misalnya, menggunakan kunci layar perangkat), promise navigator.credentials.get() akan diselesaikan. Tindakan ini akan menampilkan objek PublicKeyCredential ke frontend Anda.

Promise dapat ditolak karena beberapa alasan. Anda harus menangani error ini dalam kode dengan memeriksa properti name dari objek Error:

  • NotAllowedError: Pengguna membatalkan operasi, atau tidak ada kunci sandi yang dipilih.
  • AbortError: Operasi dibatalkan, mungkin oleh kode Anda yang menggunakan AbortController.
  • Pengecualian lainnya: Terjadi error yang tidak terduga. Browser biasanya menampilkan dialog error kepada pengguna.

Objek PublicKeyCredential berisi beberapa properti. Properti utama yang relevan untuk autentikasi meliputi:

  • 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 harus diverifikasi oleh server Anda.
  • response.authenticatorData: ArrayBuffer data pengautentikasi. Kolom ini menyertakan informasi seperti ID RP.
  • response.signature: ArrayBuffer yang berisi tanda tangan. Nilai ini adalah inti kredensial dan server Anda harus memverifikasi tanda tangan ini menggunakan kunci publik yang disimpan untuk kredensial .
  • response.userHandle: ArrayBuffer yang berisi ID pengguna yang diberikan selama pendaftaran kunci sandi.
  • authenticatorAttachment: Menunjukkan apakah pengautentikasi adalah bagian dari perangkat klien (platform) atau eksternal (cross-platform). Lampiran cross-platform dapat terjadi jika pengguna login dengan ponsel. Dalam kasus tersebut, pertimbangkan untuk meminta mereka membuat kunci sandi di perangkat saat ini untuk kemudahan di masa mendatang.
  • type: Kolom ini selalu ditetapkan ke "public-key".

Untuk mengirim objek PublicKeyCredential ini ke backend, panggil metode .toJSON() terlebih dahulu. Metode ini membuat kredensial versi JSON-serializable, yang menangani konversi properti ArrayBuffer (seperti rawId, clientDataJSON, authenticatorData, signature, dan userHandle) ke string yang dienkode Base64URL dengan benar. Kemudian, gunakan JSON.stringify() untuk mengonversi objek ini menjadi string dan kirimkan dalam isi permintaan Anda ke server.

...
// Encode and serialize the PublicKeyCredential.
const _result = credential.toJSON();
const result = JSON.stringify(_result);

// Encode and send the credential to the server for verification.  
const response = await fetch('/webauthn/signinResponse', {
  method: 'post',
  credentials: 'same-origin',
  body: result
});

Memverifikasi tanda tangan

Saat menerima kredensial kunci publik, server backend Anda harus memverifikasi autentisitasnya. Hal ini meliputi:

  1. Mengurai data kredensial.
  2. Mencari kunci publik tersimpan yang terkait dengan id kredensial.
  3. Memverifikasi signature yang diterima dengan kunci publik yang disimpan.
  4. Memvalidasi data lainnya, seperti tantangan dan asal.

Sebaiknya gunakan library FIDO/WebAuthn sisi server untuk menangani operasi kriptografis ini dengan aman. Anda dapat menemukan library open source di repo GitHub awesome-webauthn.

Jika tanda tangan dan semua pernyataan lainnya valid, server dapat membuat pengguna login. Untuk mengetahui langkah-langkah validasi sisi server yang mendetail, lihat Autentikasi kunci sandi sisi server

Memberi sinyal jika kredensial yang cocok tidak ditemukan di backend

Jika server backend Anda tidak dapat menemukan kredensial dengan ID yang cocok selama login, pengguna mungkin sebelumnya telah menghapus kunci sandi ini dari server Anda, tetapi tidak dari penyedia kunci sandinya. Ketidakcocokan ini dapat menyebabkan pengalaman pengguna yang membingungkan jika penyedia kunci sandi terus menyarankan kunci sandi yang tidak lagi berfungsi dengan situs Anda. Untuk meningkatkannya, Anda harus memberi sinyal kepada penyedia kunci sandi untuk menghapus kunci sandi yang tidak digunakan lagi.

Anda dapat menggunakan metode PublicKeyCredential.signalUnknownCredential(), bagian dari Webauthn Signal API, untuk memberi tahu penyedia kunci sandi bahwa kredensial yang ditentukan telah dihapus atau tidak ada. Panggil metode statis ini di sisi klien jika server Anda menunjukkan (misalnya, dengan kode status HTTP tertentu seperti 404) bahwa ID kredensial yang ditampilkan tidak diketahui. Berikan ID RP dan ID kredensial yang tidak diketahui ke metode ini. Penyedia kunci sandi, jika mendukung sinyal, harus menghapus kunci sandi.

// Detect authentication failure due to lack of the credential
if (response.status === 404) {
  // Feature detection
  if (PublicKeyCredential.signalUnknownCredential) {
    await PublicKeyCredential.signalUnknownCredential({
      rpId: "example.com",
      credentialId: "vI0qOggiE3OT01ZRWBYz5l4MEgU0c7PmAA" // base64url encoded credential ID
    });
  } else {
    // Encourage the user to delete the passkey from the password manager nevertheless.
    ...
  }
}

Setelah autentikasi

Bergantung pada cara pengguna login, sebaiknya ikuti alur yang berbeda.

Jika pengguna telah login tanpa kunci sandi

Jika pengguna telah login ke situs Anda tanpa kunci sandi, mereka mungkin tidak memiliki kunci sandi yang terdaftar untuk akun tersebut atau di perangkat mereka saat ini. Ini adalah saat yang tepat untuk mendorong pembuatan kunci sandi. Pertimbangkan pendekatan berikut:

  • Mengupgrade sandi ke kunci sandi: Gunakan pembuatan kondisional, fitur WebAuthn yang memungkinkan browser membuat kunci sandi secara otomatis untuk pengguna setelah login sandi berhasil. Hal ini dapat meningkatkan penggunaan kunci sandi secara signifikan dengan menyederhanakan proses pembuatan. Pelajari cara kerjanya dan cara menerapkannya di Membantu pengguna menggunakan kunci sandi dengan lebih lancar
  • Meminta pembuatan kunci sandi secara manual: Dorong pengguna untuk membuat kunci sandi. Hal ini dapat efektif setelah pengguna menyelesaikan proses login yang lebih rumit, seperti autentikasi multi-faktor (MFA). Namun, hindari perintah yang berlebihan, yang dapat mengganggu pengalaman pengguna."

Untuk melihat cara mendorong pengguna membuat kunci sandi dan mempelajari praktik terbaik lainnya, lihat contoh di Menginformasikan kunci sandi kepada pengguna.

Jika pengguna telah login dengan kunci sandi

Setelah pengguna berhasil login dengan kunci sandi, Anda memiliki beberapa peluang untuk lebih meningkatkan pengalaman mereka dan mempertahankan konsistensi akun.

Mendorong pembuatan kunci sandi baru setelah autentikasi lintas perangkat

Jika pengguna login dengan kunci sandi menggunakan mekanisme lintas perangkat (misalnya, memindai kode QR dengan ponsel), kunci sandi yang digunakan mungkin tidak disimpan secara lokal di perangkat yang digunakan untuk login. Hal ini dapat terjadi jika:

  • Mereka memiliki kunci sandi, tetapi di penyedia kunci sandi yang tidak mendukung sistem operasi atau browser login.
  • Pengguna telah kehilangan akses ke penyedia kunci sandi di perangkat login, tetapi kunci sandi masih tersedia di perangkat lain.

Dalam situasi ini, pertimbangkan untuk meminta pengguna membuat kunci sandi baru di perangkat saat ini. Hal ini dapat menghemat waktu mereka untuk mengulangi proses login lintas perangkat di masa mendatang. Untuk menentukan apakah pengguna telah login menggunakan kunci sandi lintas perangkat, periksa properti authenticatorAttachment kredensial. Jika nilainya "cross-platform", hal ini menunjukkan autentikasi lintas perangkat. Jika ya, jelaskan kemudahan membuat kunci sandi baru dan panduan mereka melalui proses pembuatan.

Menyinkronkan detail kunci sandi dengan penyedia menggunakan sinyal

Untuk memastikan konsistensi dan pengalaman pengguna yang lebih baik, Pihak Penerima (RP) Anda dapat menggunakan WebAuthn Signals API untuk menyampaikan pembaruan tentang kredensial dan informasi pengguna kepada penyedia kunci sandi.

Misalnya, agar daftar kunci sandi pengguna penyedia kunci sandi tetap akurat, buat kredensial di backend tetap sinkron. Anda dapat memberi sinyal bahwa kunci sandi tidak ada lagi sehingga penyedia kunci sandi dapat menghapus kunci sandi yang tidak diperlukan.

Demikian pula, Anda dapat memberikan sinyal jika pengguna memperbarui nama pengguna atau nama tampilannya di layanan Anda, untuk membantu memastikan informasi pengguna yang ditampilkan oleh penyedia kunci sandi (misalnya, dalam dialog pemilihan akun) selalu yang terbaru.

Untuk mempelajari lebih lanjut praktik yang baik agar kunci sandi tetap konsisten, lihat Memastikan kunci sandi konsisten dengan kredensial di server Anda dengan Signal API.

Jangan meminta faktor kedua

Kunci sandi menawarkan perlindungan bawaan yang andal terhadap ancaman umum seperti phishing. Oleh karena itu, faktor autentikasi kedua tidak menambahkan nilai keamanan yang signifikan. Sebaliknya, tindakan ini akan membuat langkah yang tidak perlu bagi pengguna selama login.

Checklist

  • Izinkan pengguna login dengan kunci sandi melalui isi otomatis formulir.
  • Memberi sinyal saat kredensial pencocokan kunci sandi tidak ditemukan di backend.
  • Minta pengguna untuk membuat kunci sandi secara manual jika pengguna belum membuatnya setelah login.
  • Buat kunci sandi secara otomatis (pembuatan bersyarat) setelah pengguna login dengan sandi (dan faktor kedua).
  • Minta pembuatan kunci sandi lokal jika pengguna telah login dengan kunci sandi lintas perangkat.
  • Sinyal daftar kunci sandi yang tersedia dan detail pengguna yang diperbarui (nama pengguna, nama tampilan) ke penyedia setelah login atau saat perubahan terjadi.

Resource