Login dengan kunci sandi melalui isi otomatis formulir

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

Kunci sandi menggantikan sandi dan membuat akun pengguna di web lebih aman, lebih mudah, dan lebih mudah digunakan. Namun, transisi dari autentikasi berbasis sandi ke 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 hanya dengan menggunakan sidik jari, wajah, atau PIN perangkat.

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

Namun, transisi dari sandi ke autentikasi berbasis kunci sandi dapat menjadi tantangan. Saat pengguna beralih ke kunci sandi, akan ada pengguna yang menggunakan sandi dan situs yang harus mengakomodasi kedua jenis pengguna tersebut. Pengguna seharusnya tidak ingat situs mana yang telah mereka ganti ke kunci sandi, jadi meminta pengguna untuk memilih metode yang akan digunakan sejak awal akan memberikan UX yang buruk.

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

UI Bersyarat

Untuk membangun pengalaman pengguna yang efisien bagi pengguna kunci sandi dan sandi, Anda dapat menyertakan kunci sandi dalam saran isi otomatis. Hal 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 menyoroti 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 kunci sandi jika mereka memilikinya.

Cara kerjanya

Untuk mengautentikasi dengan kunci sandi, gunakan WebAuthn API.

Keempat komponen dalam alur autentikasi kunci sandi adalah: pengguna:

  • Backend: Server backend yang menyimpan database akun yang menyimpan kunci publik dan metadata lainnya tentang kunci sandi tersebut.
  • Frontend: Frontend Anda yang berkomunikasi dengan browser dan mengirimkan permintaan pengambilan ke backend.
  • Browser: Browser pengguna yang menjalankan JavaScript Anda.
  • Pengautentikasi: Pengautentikasi pengguna yang membuat dan menyimpan kunci sandi. Ini mungkin dilakukan di perangkat yang sama dengan browser (misalnya saat menggunakan Windows Hello) atau di perangkat lain, seperti ponsel.
Diagram autentikasi kunci sandi
  1. Setelah pengguna sampai di frontend, sistem akan meminta verifikasi login 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 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 dalam database. Jika berhasil, pengguna akan login.

Prasyarat

UI WebAuthn bersyarat 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.

Mengautentikasi dengan kunci sandi melalui isi otomatis formulir

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

Anotasi 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 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  
  }  
}  

Mengambil verifikasi login dari server RP

Ambil verifikasi login 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 abaikan setelah durasi tertentu atau setelah upaya login gagal memvalidasi. Anggaplah ini 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". Defaultnya adalah "preferred", yang berarti pengautentikasi dapat melewati verifikasi pengguna. Tetapkan string 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 domainnya 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 bersyarat.

Mengirim kredensial kunci publik yang ditampilkan ke server RP

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

Promise dapat ditolak karena beberapa alasan berbeda. Anda perlu menangani error sebagaimana mestinya, 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 tantangan dan asal yang perlu diverifikasi oleh server RP.
  • response.authenticatorData: ArrayBuffer data pengautentikasi. Kolom ini berisi informasi seperti ID RP.
  • response.signature: ArrayBuffer dari 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 harus 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, sebaiknya minta mereka untuk 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

Setelah 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 mengagumkan-webauth.

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

Referensi