Login dengan kunci sandi melalui isi otomatis formulir

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

Kunci sandi menggantikan sandi dan membuat akun pengguna di web lebih aman, mudah, 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 menciptakan pengalaman terpadu.

Mengapa menggunakan isi otomatis formulir untuk login dengan kunci sandi?

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

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

Namun, transisi dari autentikasi berbasis sandi ke kunci sandi dapat menjadi tantangan. Saat pengguna beralih ke kunci sandi, masih ada orang yang menggunakan sandi dan situs yang harus mengakomodasi kedua jenis pengguna tersebut. Pengguna seharusnya tidak diharapkan untuk mengingat situs tempat mereka beralih ke kunci sandi. Oleh karena itu, meminta pengguna memilih metode yang akan digunakan di awal akan dianggap sebagai UX yang buruk.

Kunci sandi juga merupakan teknologi baru. Menjelaskan dan memastikan pengguna merasa nyaman menggunakannya bisa menjadi tantangan bagi {i>website<i}. Kami dapat mengandalkan pengalaman pengguna yang sudah dikenal untuk mengisi otomatis sandi guna menyelesaikan kedua masalah.

UI kondisional

Untuk membangun 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 tersimpan 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 sudah ada seolah-olah tidak ada yang berubah, tetapi dengan manfaat keamanan tambahan kunci sandi jika mereka memilikinya.

Cara kerjanya

Untuk melakukan autentikasi dengan kunci sandi, gunakan 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.
  • Pengautentikasi: 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, pengguna akan meminta tantangan dari backend untuk melakukan autentikasi 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 diselesaikan dan kredensial kunci publik ditampilkan ke frontend.
  4. Frontend mengirimkan kredensial kunci publik ke backend. Backend memverifikasi tanda tangan terhadap kunci publik akun yang cocok di database. Jika berhasil, pengguna akan login.

Prasyarat

UI WebAuthn kondisional didukung secara publik di Safari pada iOS 16, iPadOS 16, dan macOS Ventura. Fitur ini juga tersedia di Chrome di Android, macOS, dan Windows 11 22H2.

Melakukan autentikasi dengan kunci sandi melalui isi otomatis formulir

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

Anotasi kolom input formulir

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

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

Deteksi fitur

Sebelum memanggil panggilan WebAuthn API bersyarat, periksa apakah:

  • Browser mendukung WebAuthn.
  • Browser mendukung UI kondisional WebAuthn.
// 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  
  }  
}  

Ambil tantangan 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 verifikasi login baru pada setiap upaya login dan abaikan setelah durasi tertentu atau setelah upaya login gagal memvalidasi. Anggap saja seperti token CSRF.
  • allowCredentials: Array kredensial yang dapat diterima untuk autentikasi ini. Teruskan array kosong untuk memungkinkan pengguna 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". Defaultnya adalah "preferred", yang berarti pengautentikasi mungkin melewati verifikasi pengguna. Tetapkan ini ke "preferred" atau hapus properti.

Memanggil WebAuthn API dengan flag 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 menentukan mediation: 'conditional' untuk membuat permintaan menjadi bersyarat.

Mengirim kredensial kunci publik yang ditampilkan ke server RP

Setelah pengguna memilih akun dan memberikan izin menggunakan kunci layar perangkat, promise akan di-resolve dengan menampilkan objek PublicKeyCredential ke frontend RP.

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

  • NotAllowedError: Pengguna telah membatalkan operasi.
  • Pengecualian lainnya: Terjadi sesuatu yang tidak terduga. Browser akan 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 ID kredensial.
  • response.clientDataJSON: ArrayBuffer data klien. Kolom ini berisi informasi seperti tantangan 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 saat kredensial ini berasal dari perangkat lokal. Atau 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 encoding sebagian menggunakan base64url.

Memverifikasi tanda tangan

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

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 repo GitHub webauth yang mengagumkan.

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

Referensi