เจาะลึกข้อมูลเข้าสู่ระบบที่ค้นพบได้

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

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

หากต้องการให้ระบบสร้างข้อมูลเข้าสู่ระบบเป็นพาสคีย์ (ข้อมูลเข้าสู่ระบบที่ค้นพบได้) ให้ระบุ residentKey และ requireResidentKey เมื่อสร้างข้อมูลเข้าสู่ระบบ

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

UI ตัวเลือกบัญชี เช่น UI ที่กล่าวถึงก่อนหน้านี้ จะไม่แสดงข้อมูลเข้าสู่ระบบที่ค้นพบไม่ได้

requireResidentKey และ residentKey

หากต้องการสร้างพาสคีย์ ให้ระบุ authenticatorSelection.residentKey และ authenticatorSelection.requireResidentKey ใน navigator.credentials.create() โดยมีค่าดังนี้

async function register () {
  // ...

  const publicKeyCredentialCreationOptions = {
    // ...
    authenticatorSelection: {
      authenticatorAttachment: 'platform',
      residentKey: 'required',
      requireResidentKey: true,
    }
  };

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

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;

  // ...
}

residentKey:

  • 'required': ต้องสร้างข้อมูลเข้าสู่ระบบที่ค้นพบได้ หากสร้างไม่ได้ ระบบจะแสดง NotSupportedError
  • 'preferred': RP ต้องการสร้างข้อมูลเข้าสู่ระบบที่ค้นพบได้ แต่ก็ยอมรับข้อมูลเข้าสู่ระบบที่ค้นพบไม่ได้
  • 'discouraged': RP ต้องการสร้างข้อมูลเข้าสู่ระบบที่ค้นพบไม่ได้ แต่ยอมรับข้อมูลเข้าสู่ระบบที่ค้นพบได้

requireResidentKey:

  • ระบบจะเก็บพร็อพเพอร์ตี้นี้ไว้เพื่อความเข้ากันได้แบบย้อนหลังจาก WebAuthn ระดับ 1 ซึ่งเป็นข้อกำหนดเวอร์ชันเก่า ตั้งค่าเป็น true หาก residentKey เป็น 'required' มิเช่นนั้นให้ตั้งค่าเป็น false

allowCredentials

RP สามารถใช้ allowCredentials ใน navigator.credentials.get() เพื่อควบคุมประสบการณ์การตรวจสอบสิทธิ์ด้วยพาสคีย์ โดยปกติแล้ว ประสบการณ์การตรวจสอบสิทธิ์ด้วยพาสคีย์จะมี 3 ประเภท ได้แก่

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

หากต้องการมอบประสบการณ์การใช้งานนี้ ให้ละเว้นหรือส่งอาร์เรย์ว่างไปยังพารามิเตอร์ allowCredentials ใน navigator.credentials.get()

async function authenticate() {
  // ...

  const publicKeyCredentialRequestOptions = {
    // Server generated challenge:
    challenge: ****,
    // The same RP ID as used during registration:
    rpId: 'example.com',
    // You can omit `allowCredentials` as well:
    allowCredentials: []
  };

  const credential = await navigator.credentials.get({
    publicKey: publicKeyCredentialRequestOptions,
    signal: abortController.signal
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;
  
  // ...
}

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

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

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

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

หากต้องการมอบประสบการณ์การใช้งานนี้ นอกเหนือจากการส่งอาร์เรย์ว่างไปยังพร็อพเพอร์ตี้ allowCredentials หรือละเว้นพารามิเตอร์แล้ว ให้ระบุ mediation: 'conditional' ใน navigator.credentials.get() และใส่คำอธิบายประกอบในช่องป้อนข้อมูล HTML username ด้วย autocomplete="username webauthn" หรือช่องป้อนข้อมูล password ด้วย autocomplete="password webauthn"

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

async function authenticate() {
  // ...

  const publicKeyCredentialRequestOptions = {
    // Server generated challenge:
    challenge: ****,
    // The same RP ID as used during registration:
    rpId: 'example.com',
    // You can omit `allowCredentials` as well:
    allowCredentials: []
  };

  const cred = await navigator.credentials.get({
    publicKey: publicKeyCredentialRequestOptions,
    signal: abortController.signal,
    // Specify 'conditional' to activate conditional UI
    mediation: 'conditional'
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;
  
  // ...
}
<input type="text" name="username" autocomplete="username webauthn" ...>

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

การตรวจสอบสิทธิ์ซ้ำ

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

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

หากต้องการมอบประสบการณ์ของผู้ใช้ ให้ระบุรายการรหัสข้อมูลเข้าสู่ระบบสำหรับผู้ใช้ที่ลงชื่อเข้าใช้ RP ควรจะค้นหาข้อมูลได้เนื่องจากระบบรู้จักผู้ใช้แล้ว ระบุรหัสข้อมูลเข้าสู่ระบบเป็นออบเจ็กต์ PublicKeyCredentialDescriptor ในพร็อพเพอร์ตี้ allowCredentials ใน navigator.credentials.get()

async function authenticate() {
  // ...

  const publicKeyCredentialRequestOptions = {
    // Server generated challenge:
    challenge: ****,
    // The same RP ID as used during registration:
    rpId: 'example.com',
    // Provide a list of PublicKeyCredentialDescriptors:
    allowCredentials: [{
      id: ****,
      type: 'public-key',
      transports: [
        'internal',
        'hybrid'
      ]
    }, {
      id: ****,
      type: 'public-key',
      transports: [
        'internal',
        'hybrid'
      ]
    }, ...]
  };

  const credential = await navigator.credentials.get({
    publicKey: publicKeyCredentialRequestOptions,
    signal: abortController.signal
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;
  
  // ...
}

ออบเจ็กต์ PublicKeyCredentialDescriptor ประกอบด้วย

  • id: รหัสของข้อมูลเข้าสู่ระบบคีย์สาธารณะที่ RP ได้รับเมื่อลงทะเบียนพาสคีย์
  • type: โดยปกติแล้วฟิลด์นี้จะเป็น 'public-key'
  • transports: คำแนะนำเกี่ยวกับ Transport ที่อุปกรณ์ซึ่งมีข้อมูลเข้าสู่ระบบนี้รองรับ ซึ่งเบราว์เซอร์ใช้เพื่อเพิ่มประสิทธิภาพ UI ที่ขอให้ผู้ใช้นำเสนออุปกรณ์ภายนอก หากระบุไว้ รายการนี้ควรมีผลลัพธ์ของการเรียก getTransports() ระหว่างการลงทะเบียนข้อมูลเข้าสู่ระบบแต่ละรายการ

สรุป

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

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

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