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

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

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

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

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

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() และใส่คำอธิบายประกอบช่องอินพุต username ของ HTML ด้วย autocomplete="username webauthn" หรือช่องอินพุต password ด้วย autocomplete="password webauthn"

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

สรุป

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

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

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