สร้างพาสคีย์สำหรับการเข้าสู่ระบบแบบไม่ต้องใช้รหัสผ่าน

พาสคีย์ช่วยให้บัญชีผู้ใช้ปลอดภัยขึ้น ง่ายขึ้น และใช้งานง่ายขึ้น

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

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

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

ระบบจะขอให้ผู้ใช้สร้างพาสคีย์ในกรณีต่อไปนี้

  • เมื่อผู้ใช้ลงชื่อเข้าใช้ด้วยรหัสผ่าน
  • เมื่อผู้ใช้ลงชื่อเข้าใช้ด้วยพาสคีย์จากอุปกรณ์อื่น (ซึ่งก็คือ authenticatorAttachment คือ cross-platform)
  • ในหน้าเฉพาะที่ผู้ใช้จัดการพาสคีย์ได้

หากต้องการสร้างพาสคีย์ ให้ใช้ WebAuthn API

องค์ประกอบ 4 อย่างของขั้นตอนการลงทะเบียนพาสคีย์ ได้แก่

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

เส้นทางในการเพิ่มพาสคีย์ใหม่ลงในบัญชีผู้ใช้ที่มีอยู่มีดังนี้

  1. ผู้ใช้ลงชื่อเข้าใช้เว็บไซต์
  2. เมื่อลงชื่อเข้าใช้แล้ว ผู้ใช้จะขอสร้างพาสคีย์ที่ส่วนหน้า เช่น ด้วยการกดปุ่ม "สร้างพาสคีย์"
  3. ฟรอนท์เอนด์จะขอข้อมูลจากแบ็กเอนด์เพื่อสร้างพาสคีย์ เช่น ข้อมูลผู้ใช้ คำถาม และรหัสข้อมูลเข้าสู่ระบบที่จะยกเว้น
  4. ฟรอนท์เอนด์จะเรียกใช้ navigator.credentials.create() เพื่อสร้างพาสคีย์ การโทรนี้จะส่งคืนคำสัญญา
  5. ระบบจะสร้างพาสคีย์ขึ้นหลังจากที่ผู้ใช้ให้ความยินยอมโดยใช้การล็อกหน้าจอของอุปกรณ์ คำมั่นสัญญาได้รับการแก้ไขแล้วและระบบส่งข้อมูลรับรองคีย์สาธารณะกลับไปยังฟรอนท์เอนด์
  6. ฟรอนท์เอนด์จะส่งข้อมูลเข้าสู่ระบบคีย์สาธารณะไปยังแบ็กเอนด์และจัดเก็บรหัสข้อมูลเข้าสู่ระบบและคีย์สาธารณะที่เชื่อมโยงกับบัญชีผู้ใช้เพื่อการตรวจสอบสิทธิ์ในอนาคต

ความเข้ากันได้

เบราว์เซอร์ส่วนใหญ่รองรับ WebAuthn แต่มีช่องโหว่เล็กๆ น้อยๆ โปรดไปที่การสนับสนุนอุปกรณ์ -พาสคีย์s.dev เพื่อดูการผสมผสานระหว่างเบราว์เซอร์และระบบปฏิบัติการที่รองรับการสร้างพาสคีย์

สร้างพาสคีย์ใหม่

ฟรอนท์เอนด์ควรดำเนินการอย่างไรเมื่อมีการส่งคำขอสร้างพาสคีย์ใหม่

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

ก่อนแสดงปุ่ม "สร้างพาสคีย์ใหม่" ให้ตรวจสอบดังนี้

  • เบราว์เซอร์รองรับ WebAuthn
  • อุปกรณ์รองรับ Authenticator ของแพลตฟอร์ม (สร้างพาสคีย์และตรวจสอบสิทธิ์ด้วยพาสคีย์ได้)
  • เบราว์เซอร์รองรับ UI แบบมีเงื่อนไขของ WebAuthn
// Availability of `window.PublicKeyCredential` means WebAuthn is usable.  
// `isUserVerifyingPlatformAuthenticatorAvailable` means the feature detection is usable.  
// `​​isConditionalMediationAvailable` means the feature detection is usable.  
if (window.PublicKeyCredential &&  
    PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable &&  
    PublicKeyCredential.​​isConditionalMediationAvailable) {  
  // Check if user verifying platform authenticator is available.  
  Promise.all([  
    PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(),  
    PublicKeyCredential.​​isConditionalMediationAvailable(),  
  ]).then(results => {  
    if (results.every(r => r === true)) {  
      // Display "Create a new passkey" button  
    }  
  });  
}  

เบราว์เซอร์นี้ไม่รองรับพาสคีย์จนกว่าจะเป็นไปตามเงื่อนไขทั้งหมด ไม่ควรแสดงปุ่ม "สร้างพาสคีย์ใหม่" จนกว่าจะถึงเวลาดังกล่าว

ดึงข้อมูลที่สำคัญจากแบ็กเอนด์

เมื่อผู้ใช้คลิกปุ่ม ให้ดึงข้อมูลสำคัญเพื่อโทรหา navigator.credentials.create() จากแบ็กเอนด์ ดังนี้

  • challenge: ระบบทดสอบที่เซิร์ฟเวอร์สร้างขึ้นใน ArrayBuffer สำหรับการลงทะเบียนนี้ ขั้นตอนนี้จำเป็น แต่ไม่มีการใช้งานระหว่างการลงทะเบียน เว้นแต่จะทำเอกสารรับรอง ซึ่งเป็นหัวข้อขั้นสูงที่ไม่ได้กล่าวถึงที่นี่
  • user.id: รหัสที่ไม่ซ้ำกันของผู้ใช้ ค่านี้ต้องเป็น ArrayBuffer ซึ่งไม่มีข้อมูลส่วนบุคคลที่ระบุตัวบุคคลนั้นได้ เช่น อีเมลหรือชื่อผู้ใช้ ค่า 16 ไบต์แบบสุ่มที่สร้างขึ้นต่อบัญชีจะทำงานได้ดี
  • user.name: ช่องนี้ควรมีตัวระบุที่ไม่ซ้ำสำหรับบัญชีที่ผู้ใช้จะรู้จัก เช่น อีเมลหรือชื่อผู้ใช้ ข้อมูลนี้จะแสดง ในตัวเลือกบัญชี (หากใช้ชื่อผู้ใช้ ให้ใช้ค่าเดียวกับในการตรวจสอบสิทธิ์รหัสผ่าน)
  • user.displayName: ฟิลด์นี้เป็นชื่อที่ต้องระบุและใช้งานง่ายยิ่งขึ้นสำหรับบัญชี ซึ่งไม่จำเป็นต้องไม่ซ้ำกัน และอาจเป็นชื่อที่ผู้ใช้เลือก หากเว็บไซต์ไม่มีค่าที่เหมาะสมที่จะใส่ที่นี่ ให้ส่งสตริงว่าง ข้อมูลนี้อาจแสดงบนตัวเลือกบัญชี โดยขึ้นอยู่กับเบราว์เซอร์
  • excludeCredentials: ป้องกันการลงทะเบียนอุปกรณ์เดียวกันโดยการระบุรายการรหัสข้อมูลเข้าสู่ระบบที่ลงทะเบียนไว้แล้ว สมาชิก transports (หากมี) ควรแสดงผลลัพธ์ของการเรียกใช้ getTransports() ในระหว่างการลงทะเบียนข้อมูลเข้าสู่ระบบแต่ละรายการ

เรียกใช้ WebAuthn API เพื่อสร้างพาสคีย์

โทร navigator.credentials.create() เพื่อสร้างพาสคีย์ใหม่ API จะแสดงผลสัญญา โดยรอการโต้ตอบของผู้ใช้ที่แสดงกล่องโต้ตอบโมดัล

const publicKeyCredentialCreationOptions = {
  challenge: *****,
  rp: {
    name: "Example",
    id: "example.com",
  },
  user: {
    id: *****,
    name: "john78",
    displayName: "John",
  },
  pubKeyCredParams: [{alg: -7, type: "public-key"},{alg: -257, type: "public-key"}],
  excludeCredentials: [{
    id: *****,
    type: 'public-key',
    transports: ['internal'],
  }],
  authenticatorSelection: {
    authenticatorAttachment: "platform",
    requireResidentKey: true,
  }
};

const credential = await navigator.credentials.create({
  publicKey: publicKeyCredentialCreationOptions
});

// Encode and send the credential to the server for verification.  

พารามิเตอร์ที่ไม่ได้อธิบายไว้ข้างต้น ได้แก่

  • rp.id: รหัส RP คือโดเมนและเว็บไซต์สามารถระบุโดเมนของตนหรือส่วนต่อท้ายที่ลงทะเบียนได้ ตัวอย่างเช่น หากต้นทางของ RP คือ https://login.example.com:1337 รหัส RP อาจเป็น login.example.com หรือ example.com ก็ได้ หากระบุรหัส RP เป็น example.com ผู้ใช้จะตรวจสอบสิทธิ์ใน login.example.com หรือโดเมนย่อยใดก็ได้ใน example.com

  • rp.name: ชื่อของ RP

  • pubKeyCredParams: ช่องนี้ระบุอัลกอริทึมคีย์สาธารณะที่รองรับของ RP เราขอแนะนำให้ตั้งค่าเป็น [{alg: -7, type: "public-key"},{alg: -257, type: "public-key"}] ข้อมูลนี้ระบุการรองรับ ECDSA ที่มี P-256 และ RSA PKCS#1 และการสนับสนุนเหล่านี้จะครอบคลุมอย่างครบถ้วน

  • authenticatorSelection.authenticatorAttachment: ตั้งค่าเป็น "platform" หากการสร้างพาสคีย์นี้เป็นการอัปเกรดจากรหัสผ่าน เช่น ในโปรโมชันหลังจากลงชื่อเข้าใช้ "platform" ระบุว่า RP ต้องการตัวตรวจสอบสิทธิ์แพลตฟอร์ม (Authenticator ที่ฝังอยู่ในอุปกรณ์แพลตฟอร์ม) และจะไม่แจ้งให้เสียบ เช่น คีย์ความปลอดภัย USB ผู้ใช้มีตัวเลือกที่ง่ายกว่าในการสร้างพาสคีย์

  • authenticatorSelection.requireResidentKey: ตั้งค่าเป็นบูลีน "จริง" ข้อมูลเข้าสู่ระบบที่ค้นพบได้ (คีย์ผู้พำนักอาศัย) จะเก็บข้อมูลผู้ใช้ไว้ในพาสคีย์และอนุญาตให้ผู้ใช้เลือกบัญชีได้เมื่อตรวจสอบสิทธิ์

  • authenticatorSelection.userVerification: ระบุว่าการยืนยันผู้ใช้โดยใช้การล็อกหน้าจออุปกรณ์คือ "required", "preferred" หรือ "discouraged" ค่าเริ่มต้นคือ "preferred" ซึ่งหมายความว่า Authenticator อาจข้ามการยืนยันผู้ใช้ ตั้งค่านี้เป็น "preferred" หรือละเว้นพร็อพเพอร์ตี้

ส่งข้อมูลเข้าสู่ระบบคีย์สาธารณะที่ส่งคืนไปยังแบ็กเอนด์

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

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

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

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

  • id: รหัส Base64URL ที่เข้ารหัสของพาสคีย์ที่สร้างขึ้น รหัสนี้ช่วยให้เบราว์เซอร์ระบุได้ว่ามีพาสคีย์ที่ตรงกันในอุปกรณ์หรือไม่เมื่อตรวจสอบสิทธิ์ คุณจะต้องจัดเก็บค่านี้ไว้ในฐานข้อมูลบนแบ็กเอนด์
  • rawId: เวอร์ชัน ArrayBuffer ของรหัสข้อมูลเข้าสู่ระบบ
  • response.clientDataJSON: ข้อมูลไคลเอ็นต์ที่เข้ารหัสด้วย ArrayBuffer
  • response.attestationObject: ออบเจ็กต์เอกสารรับรองที่เข้ารหัสแบบ ArrayBuffer ซึ่งประกอบด้วยข้อมูลสำคัญ เช่น รหัส RP, แฟล็ก และคีย์สาธารณะ
  • authenticatorAttachment: ส่งคืน "platform" เมื่อสร้างข้อมูลเข้าสู่ระบบนี้ในอุปกรณ์ที่รองรับพาสคีย์
  • type: ช่องนี้ตั้งค่าเป็น "public-key" เสมอ

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

บันทึกข้อมูลเข้าสู่ระบบ

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

จากนั้น คุณสามารถจัดเก็บข้อมูลที่ได้จากข้อมูลเข้าสู่ระบบไปยังฐานข้อมูลไว้ใช้ในอนาคตได้ รายการต่อไปนี้เป็นพร็อพเพอร์ตี้ทั่วไปบางรายการที่จะบันทึก

  • รหัสข้อมูลเข้าสู่ระบบ (คีย์หลัก)
  • User ID
  • คีย์สาธารณะ

ข้อมูลเข้าสู่ระบบคีย์สาธารณะยังมีข้อมูลต่อไปนี้ซึ่งคุณอาจต้องการบันทึกไว้ในฐานข้อมูลด้วย

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

แหล่งข้อมูล