ลงชื่อเข้าใช้ด้วยพาสคีย์ผ่านการป้อนแบบฟอร์มอัตโนมัติ

สร้างประสบการณ์การลงชื่อเข้าใช้ที่ใช้ประโยชน์จากพาสคีย์โดยที่ยังให้ความช่วยเหลือผู้ใช้รหัสผ่านเดิมได้อยู่

พาสคีย์จะแทนที่รหัสผ่าน และทำให้บัญชีผู้ใช้บนเว็บปลอดภัยขึ้น เรียบง่ายกว่าเดิม และใช้งานง่ายขึ้น อย่างไรก็ตาม การเปลี่ยนจากการตรวจสอบสิทธิ์แบบใช้รหัสผ่านเป็นพาสคีย์อาจทำให้ประสบการณ์ของผู้ใช้มีความซับซ้อนขึ้น การใช้การป้อนแบบฟอร์มอัตโนมัติเพื่อแนะนำพาสคีย์ช่วยสร้างประสบการณ์ใช้งานที่เป็นหนึ่งเดียวได้

เหตุใดจึงควรใช้การป้อนข้อความอัตโนมัติในแบบฟอร์มเพื่อลงชื่อเข้าใช้ด้วยพาสคีย์

เมื่อใช้พาสคีย์ ผู้ใช้จะลงชื่อเข้าใช้เว็บไซต์ได้เพียงแค่ใช้ลายนิ้วมือ ใบหน้า หรือ PIN ของอุปกรณ์

ตามหลักแล้ว ไม่ควรมีผู้ใช้รหัสผ่าน และขั้นตอนการตรวจสอบสิทธิ์อาจทำได้ง่ายๆ อย่างปุ่มลงชื่อเข้าใช้เพียงปุ่มเดียว เมื่อผู้ใช้แตะปุ่ม กล่องโต้ตอบตัวเลือกบัญชีจะปรากฏขึ้น ผู้ใช้สามารถเลือกบัญชี ปลดล็อกหน้าจอเพื่อยืนยัน และลงชื่อเข้าใช้ได้

แต่การเปลี่ยนจากรหัสผ่านไปใช้การตรวจสอบสิทธิ์ด้วยพาสคีย์อาจเป็นเรื่องยาก เมื่อผู้ใช้เปลี่ยนไปใช้พาสคีย์ ผู้ใช้ทั้ง 2 ประเภทจะยังใช้รหัสผ่านและเว็บไซต์ต้องรองรับผู้ใช้ทั้ง 2 ประเภท ผู้ใช้ไม่ควรต้องจดจำว่าได้เปลี่ยนมาใช้พาสคีย์ในเว็บไซต์ใด ดังนั้นการขอให้ผู้ใช้เลือกวิธีที่จะใช้ตั้งแต่เริ่มแรกอาจทำให้ UX แย่ลง

พาสคีย์ก็เป็นเทคโนโลยีใหม่เช่นกัน การอธิบายและตรวจสอบว่าผู้ใช้รู้สึกสบายใจที่จะใช้ส่วนขยายดังกล่าวอาจเป็นเรื่องท้าทายสำหรับเว็บไซต์ เราสามารถอาศัยประสบการณ์ของผู้ใช้ที่คุ้นเคย ในการป้อนรหัสผ่านอัตโนมัติเพื่อแก้ปัญหาทั้ง 2 อย่าง

UI แบบมีเงื่อนไข

หากต้องการสร้างประสบการณ์ของผู้ใช้ที่มีประสิทธิภาพทั้งสำหรับผู้ใช้พาสคีย์และรหัสผ่าน คุณสามารถใส่พาสคีย์ไว้ในคำแนะนำการป้อนข้อความอัตโนมัติได้ ซึ่งเรียกว่า UI แบบมีเงื่อนไข และเป็นส่วนหนึ่งของมาตรฐาน WebAuthn

ทันทีที่ผู้ใช้แตะช่องป้อนชื่อผู้ใช้ กล่องโต้ตอบคำแนะนำการป้อนข้อความอัตโนมัติจะปรากฏขึ้น ซึ่งจะไฮไลต์พาสคีย์ที่จัดเก็บไว้พร้อมกับคำแนะนำการป้อนรหัสผ่านอัตโนมัติ จากนั้นผู้ใช้สามารถเลือกบัญชีและใช้ฟีเจอร์ล็อกหน้าจอของอุปกรณ์ในการลงชื่อเข้าใช้

วิธีนี้จะช่วยให้ผู้ใช้ลงชื่อเข้าใช้เว็บไซต์ด้วยแบบฟอร์มที่มีอยู่เสมือนว่าไม่มีอะไรเปลี่ยนแปลง แต่เพิ่มประโยชน์ด้านความปลอดภัยของพาสคีย์หากมี

วิธีการทำงาน

หากต้องการตรวจสอบสิทธิ์ด้วยพาสคีย์ ให้ใช้ WebAuthn API

องค์ประกอบ 4 รายการในขั้นตอนการตรวจสอบสิทธิ์พาสคีย์ ได้แก่ ผู้ใช้

  • แบ็กเอนด์: เซิร์ฟเวอร์แบ็กเอนด์ที่เก็บฐานข้อมูลบัญชีซึ่งจัดเก็บคีย์สาธารณะและข้อมูลเมตาอื่นๆ เกี่ยวกับพาสคีย์
  • ฟรอนท์เอนด์: ฟรอนท์เอนด์ซึ่งสื่อสารกับเบราว์เซอร์และส่งคำขอดึงข้อมูลไปยังแบ็กเอนด์
  • เบราว์เซอร์: เบราว์เซอร์ของผู้ใช้ที่เรียกใช้ JavaScript
  • Authenticator: Authenticator ของผู้ใช้ที่สร้างและจัดเก็บพาสคีย์ ซึ่งอาจอยู่ในอุปกรณ์เดียวกับเบราว์เซอร์ (เช่น เมื่อใช้ Windows Hello) หรือในอุปกรณ์อื่น เช่น โทรศัพท์
แผนภาพการตรวจสอบสิทธิ์พาสคีย์
  1. เมื่อผู้ใช้ไปที่ฟรอนท์เอนด์ ผู้ใช้ก็จะส่งคำขอรับการยืนยันตัวตนจากแบ็กเอนด์เพื่อตรวจสอบสิทธิ์ด้วยพาสคีย์และการโทร navigator.credentials.get() เพื่อเริ่มการตรวจสอบสิทธิ์ด้วยพาสคีย์ การดำเนินการนี้จะแสดงผล Promise
  2. เมื่อผู้ใช้วางเคอร์เซอร์ในช่องลงชื่อเข้าใช้ เบราว์เซอร์จะแสดงกล่องโต้ตอบการป้อนรหัสผ่านอัตโนมัติ ซึ่งรวมถึงพาสคีย์ กล่องโต้ตอบการตรวจสอบสิทธิ์จะปรากฏขึ้น หากผู้ใช้เลือกพาสคีย์
  3. หลังจากที่ผู้ใช้ยืนยันตัวตนโดยใช้การล็อกหน้าจอของอุปกรณ์ ระบบจะปิดล็อกและสามารถแสดงข้อมูลเข้าสู่ระบบของคีย์สาธารณะไปยังฟรอนท์เอนด์
  4. ฟรอนท์เอนด์จะส่งข้อมูลเข้าสู่ระบบคีย์สาธารณะไปยังแบ็กเอนด์ แบ็กเอนด์จะตรวจสอบลายเซ็นกับคีย์สาธารณะของบัญชีที่ตรงกันในฐานข้อมูล หากยืนยันสำเร็จ ผู้ใช้จะลงชื่อเข้าใช้

ข้อกำหนดเบื้องต้น

UI ของ WebAuthn แบบมีเงื่อนไขได้รับการรองรับแบบสาธารณะใน Safari ใน iOS 16, iPadOS 16 และ macOS Ventura นอกจากนี้ยังพร้อมใช้งานบน Chrome บน Android, macOS และ Windows 11 22H2 ด้วย

ตรวจสอบสิทธิ์ด้วยพาสคีย์ผ่านการป้อนแบบฟอร์มอัตโนมัติ

เมื่อผู้ใช้ต้องการลงชื่อเข้าใช้ คุณสามารถเรียกใช้ WebAuthn ใน get แบบมีเงื่อนไขได้ เพื่อระบุว่าอาจมีพาสคีย์ในคำแนะนำการป้อนข้อความอัตโนมัติ การเรียกใช้ API ของ WebAuthn navigator.credentials.get() แบบมีเงื่อนไขจะไม่แสดง UI และยังคงรอดำเนินการจนกว่าผู้ใช้จะเลือกบัญชีให้ลงชื่อเข้าใช้จากคำแนะนำของการป้อนข้อความอัตโนมัติ หากผู้ใช้เลือกพาสคีย์ เบราว์เซอร์จะแก้คำมั่นสัญญาด้วยข้อมูลรับรองแทนการกรอกแบบฟอร์มลงชื่อเข้าใช้ หน้านั้นเป็นความรับผิดชอบ ที่จะต้องลงชื่อเข้าใช้ให้ผู้ใช้

ใส่คำอธิบายประกอบในช่องใส่ฟอร์ม

เพิ่มแอตทริบิวต์ autocomplete ลงในช่องชื่อผู้ใช้ input หากจำเป็น เพิ่ม username และ webauthn เป็นโทเค็นเพื่อให้ผู้ให้บริการแนะนำพาสคีย์

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

การตรวจหาฟีเจอร์

ก่อนเรียกใช้การเรียก WebAuthn API แบบมีเงื่อนไข ให้ตรวจสอบว่า

  • เบราว์เซอร์รองรับ WebAuthn
  • เบราว์เซอร์รองรับ UI แบบมีเงื่อนไขของ 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  
  }  
}  

เรียกคำท้าจากเซิร์ฟเวอร์ RP

เรียกคำท้าจากเซิร์ฟเวอร์ RP ที่ต้องใช้ในการเรียก navigator.credentials.get():

  • challenge: ชาเลนจ์ที่เซิร์ฟเวอร์สร้างขึ้นใน ArrayBuffer วิธีนี้จำเป็นต่อการป้องกันการโจมตี การเล่นซ้ำ โปรดสร้างคำถามใหม่ทุกครั้งที่ลงชื่อเข้าใช้ และไม่ต้องสนใจคำถามหลังจากช่วงเวลาหนึ่งหรือหลังจากพยายามลงชื่อเข้าใช้แล้วไม่สำเร็จ ให้คิดว่านี่เป็นโทเค็น CSRF
  • allowCredentials: อาร์เรย์ของข้อมูลเข้าสู่ระบบที่ยอมรับได้สำหรับการตรวจสอบสิทธิ์นี้ ส่งผ่านอาร์เรย์ที่ว่างเปล่าเพื่อให้ผู้ใช้เลือกพาสคีย์ที่ใช้ได้จากรายการที่เบราว์เซอร์แสดง
  • userVerification: ระบุว่าการยืนยันผู้ใช้โดยใช้การล็อกหน้าจอของอุปกรณ์คือ "required", "preferred" หรือ "discouraged" ค่าเริ่มต้นคือ "preferred" ซึ่งหมายความว่า Authenticator อาจข้ามการยืนยันผู้ใช้ไป โปรดตั้งค่าเป็น "preferred" หรือข้ามพร็อพเพอร์ตี้ไป

เรียกใช้ WebAuthn API ด้วยแฟล็ก conditional เพื่อตรวจสอบสิทธิ์ผู้ใช้

โทรไปที่ navigator.credentials.get() เพื่อเริ่มรอการตรวจสอบสิทธิ์ผู้ใช้

// 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: รหัส RP คือโดเมนและเว็บไซต์จะระบุโดเมนหรือคำต่อท้ายที่จดทะเบียนได้ ค่านี้ต้องตรงกับ rp.id ที่ใช้เมื่อสร้างพาสคีย์

อย่าลืมระบุ mediation: 'conditional' เพื่อทำให้คำขอมีเงื่อนไข

ส่งข้อมูลเข้าสู่ระบบคีย์สาธารณะที่ส่งคืนไปยังเซิร์ฟเวอร์ RP

หลังจากที่ผู้ใช้เลือกบัญชีและให้ความยินยอมโดยใช้การล็อกหน้าจอของอุปกรณ์แล้ว คำสัญญาจะได้รับการแก้ไขโดยส่งกลับออบเจ็กต์ PublicKeyCredential ไปยังฟรอนท์เอนด์ของ RP

ระบบอาจปฏิเสธสัญญาได้ด้วยเหตุผลหลายประการ คุณต้องจัดการข้อผิดพลาดให้สอดคล้องกันโดยขึ้นอยู่กับพร็อพเพอร์ตี้ name ของออบเจ็กต์ Error ดังนี้

  • NotAllowedError: ผู้ใช้ยกเลิกการดำเนินการ
  • ข้อยกเว้นอื่นๆ: มีบางอย่างที่ไม่คาดคิดเกิดขึ้น เบราว์เซอร์จะแสดงกล่องโต้ตอบ ข้อผิดพลาดแก่ผู้ใช้

ออบเจ็กต์ข้อมูลเข้าสู่ระบบคีย์สาธารณะมีพร็อพเพอร์ตี้ต่อไปนี้

  • id: รหัสที่เข้ารหัส base64url ของข้อมูลเข้าสู่ระบบพาสคีย์ที่ตรวจสอบสิทธิ์แล้ว
  • rawId: รหัสข้อมูลเข้าสู่ระบบเวอร์ชัน ArrayBuffer
  • response.clientDataJSON: ArrayBuffer ของข้อมูลไคลเอ็นต์ ช่องนี้มีข้อมูล เช่น ความท้าทายและต้นทางที่เซิร์ฟเวอร์ RP จะต้องยืนยัน
  • response.authenticatorData: ArrayBuffer ของข้อมูล Authenticator ช่องนี้มีข้อมูลอย่างเช่น RPID
  • response.signature: ArrayBuffer ของลายเซ็น ค่านี้คือหัวใจสำคัญของข้อมูลเข้าสู่ระบบและต้องได้รับการยืนยันบนเซิร์ฟเวอร์
  • response.userHandle: ArrayBuffer ที่มีรหัสผู้ใช้ที่ตั้งค่าไว้ ณ เวลาที่สร้าง คุณจะใช้ค่านี้แทนรหัสข้อมูลเข้าสู่ระบบได้ หากเซิร์ฟเวอร์จำเป็นต้องเลือกค่ารหัสที่เซิร์ฟเวอร์จะใช้ หรือหากแบ็กเอนด์ไม่ต้องการสร้างดัชนีในรหัสข้อมูลเข้าสู่ระบบ
  • authenticatorAttachment: ส่งคืน platform เมื่อข้อมูลเข้าสู่ระบบนี้มาจากอุปกรณ์ในเครือข่ายเดียวกัน หรือในกรณีที่เป็น cross-platform โดยเฉพาะกรณีที่ผู้ใช้ใช้โทรศัพท์เพื่อลงชื่อเข้าใช้ หากผู้ใช้จำเป็นต้องใช้โทรศัพท์ในการลงชื่อเข้าใช้ ลองแจ้งให้ผู้ใช้สร้างพาสคีย์ในอุปกรณ์ภายใน
  • type: ระบบจะตั้งค่าช่องนี้เป็น "public-key" เสมอ

หากคุณใช้ไลบรารีในการจัดการออบเจ็กต์ข้อมูลเข้าสู่ระบบคีย์สาธารณะในเซิร์ฟเวอร์ RP เราขอแนะนำให้คุณส่งออบเจ็กต์ทั้งหมดไปยังเซิร์ฟเวอร์หลังจากเข้ารหัสบางส่วนด้วย base64url

ยืนยันลายเซ็น

เมื่อคุณได้รับข้อมูลเข้าสู่ระบบคีย์สาธารณะบนเซิร์ฟเวอร์ ให้ส่งไปยังไลบรารี FIDO เพื่อประมวลผลออบเจ็กต์

ค้นหารหัสข้อมูลเข้าสู่ระบบที่ตรงกันซึ่งมีพร็อพเพอร์ตี้ id (หากต้องการระบุบัญชีผู้ใช้ ให้ใช้พร็อพเพอร์ตี้ userHandle ซึ่งก็คือ user.id ที่คุณระบุเมื่อสร้างข้อมูลเข้าสู่ระบบ) ดูว่าสามารถยืนยัน signature ของข้อมูลเข้าสู่ระบบด้วยคีย์สาธารณะที่จัดเก็บไว้ได้หรือไม่ ในการทำเช่นนั้น เราขอแนะนำให้ใช้ไลบรารีฝั่งเซิร์ฟเวอร์หรือโซลูชันแทนที่จะเขียนโค้ดของคุณเอง คุณจะค้นหาไลบรารีโอเพนซอร์สได้ในที่เก็บ GitHub แบบ Webauth

เมื่อยืนยันข้อมูลเข้าสู่ระบบด้วยคีย์สาธารณะที่ตรงกันแล้ว ให้ลงชื่อเข้าใช้ให้ผู้ใช้

แหล่งข้อมูล