معلومات تفصيلية حول بيانات الاعتماد القابلة للاكتشاف

تهدف بيانات اعتماد FIDO، مثل مفاتيح المرور، إلى استبدال كلمات المرور، ولكن يمكن لمعظمها أيضًا تحرير المستخدم من كتابة اسم المستخدم. يتيح ذلك للمستخدمين إجراء المصادقة عن طريق اختيار حساب من قائمة مفاتيح المرور التي يملكونها للموقع الإلكتروني الحالي.

تم تصميم الإصدارات السابقة من مفاتيح الأمان كطرق مصادقة بخطوتين، وكانت تتطلب أرقام تعريف بيانات الاعتماد المحتملة، وبالتالي تتطلب إدخال اسم مستخدم. تُسمى بيانات الاعتماد التي يمكن لمفتاح الأمان العثور عليها بدون معرفة أرقام تعريفه بيانات اعتماد قابلة للاكتشاف. تُعد معظم بيانات اعتماد FIDO التي يتم إنشاؤها اليوم بيانات اعتماد قابلة للاكتشاف، وخاصةً مفاتيح المرور المخزَّنة في مدير كلمات المرور أو على مفتاح أمان حديث.

لضمان قابلية اكتشاف بيانات الاعتماد، حدِّد residentKey وrequireResidentKey عند إنشاء مفتاح المرور.

يمكن للجهات الموثوق بها استخدام بيانات الاعتماد القابلة للاكتشاف من خلال حذف allowCredentials أثناء مصادقة مفتاح المرور. في هذه الحالات، يعرض المتصفّح أو النظام للمستخدم قائمة بمفاتيح المرور المتاحة، والتي يتم تحديدها من خلال السمة user.name التي تم ضبطها في وقت الإنشاء. إذا اختار المستخدم واحدًا، سيتم تضمين القيمة user.id في التوقيع الناتج. يمكن للخادم بعد ذلك استخدام ذلك الرقم أو معرف بيانات الاعتماد الذي تم عرضه للبحث عن الحساب بدلاً من اسم المستخدم المكتوب.

لا تعرض واجهات المستخدم لأداة اختيار الحساب، مثل تلك التي تمت مناقشتها سابقًا، بيانات اعتماد غير قابلة للاكتشاف.

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': يفضّل الجهة المحظورة إنشاء بيانات اعتماد قابلة للاكتشاف، ولكنّها تقبل بيانات الاعتماد غير القابلة للاكتشاف.
  • 'discouraged': يفضّل الجهة المحظورة إنشاء بيانات اعتماد غير قابلة للاكتشاف، ولكنّها تقبل بيانات الاعتماد القابلة للاكتشاف.

requireResidentKey:

  • يتم الاحتفاظ بهذه السمة للتوافق مع الأنظمة القديمة من المستوى 1 من WebAuthn، وهو إصدار قديم من المواصفات. يجب ضبط السمة على true إذا كانت قيمة السمة residentKey هي 'required'، وإلا سيتم ضبطها على false.

allowCredentials

يمكن للجهات المحظورة استخدام allowCredentials على navigator.credentials.get() للتحكّم في تجربة مصادقة مفاتيح المرور. هناك عادةً ثلاثة أنواع من تجارب مصادقة مفاتيح المرور:

باستخدام بيانات الاعتماد القابلة للاكتشاف، يمكن أن تعرض الجهات المحظورة أداة اختيار الحساب المشروط الخاصة بالمستخدم ليختار حسابًا لتسجيل الدخول باستخدامه، ويلي ذلك عملية إثبات هوية المستخدم. ويُعدّ هذا الإجراء مناسبًا لعملية مصادقة مفتاح المرور التي تبدأ من خلال الضغط على زر مخصّص لمصادقة مفتاح المرور.

لتحقيق تجربة المستخدم هذه، احذف صفيفًا فارغًا أو أدخِله إلى مَعلمة 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;
  
  // ...
}

عرض نموذج مفتاح مرور تلقائيًا

تعمل أداة اختيار الحسابات المشروطة الموضّحة أعلاه بشكل جيد إذا كان معظم المستخدمين يستخدمون مفاتيح المرور وكانت متاحة على الجهاز المحلي. بالنسبة إلى المستخدم الذي لا يملك مفاتيح مرور محلية، سيستمر ظهور مربّع الحوار المشروط وسيعرض على المستخدم تقديم مفتاح مرور من جهاز آخر. أثناء نقل المستخدمين إلى مفاتيح المرور، قد تحتاج إلى تجنُّب ظهور واجهة المستخدم للمستخدمين الذين لم يسبق لهم إعداد مفتاح مرور.

بدلاً من ذلك، قد يتم طي مجموعة مفتاح المرور في طلبات الملء التلقائي للحقول في نموذج تسجيل دخول تقليدي، إلى جانب أسماء المستخدمين وكلمات المرور المحفوظة. بهذه الطريقة، يمكن للمستخدم الذي لديه مفاتيح مرور "ملء" نموذج تسجيل الدخول من خلال اختيار مفتاح المرور، ويمكن للمستخدمين الذين لديهم زوج محفوظ من اسم المستخدم/كلمة المرور اختياره، ولا يمكن للمستخدمين الذين ليس لديهم أي منهما كتابة اسم المستخدم وكلمة المرور.

وتُعدّ تجربة المستخدم هذه مثالية عندما تكون الجهة المحظورة خاضعة لعملية نقل بيانات مع استخدام مزيج من كلمات المرور ومفاتيح المرور.

لتحقيق تجربة المستخدم هذه، بالإضافة إلى تمرير مصفوفة فارغة إلى السمة allowCredentials أو حذف المَعلمة، عليك تحديد mediation: 'conditional' في navigator.credentials.get() وإضافة تعليقات توضيحية إلى حقل إدخال HTML username باستخدام autocomplete="username webauthn" أو حقل إدخال password يتضمّن autocomplete="password webauthn".

لن يؤدي الطلب إلى navigator.credentials.get() إلى عرض أي واجهة مستخدم، ولكن إذا ركّز المستخدم على حقل الإدخال الذي يتضمّن تعليقات توضيحية، سيتم تضمين أي مفاتيح مرور متاحة في خيارات الملء التلقائي. إذا اختار المستخدم أحد هذه الإعدادات، سيخضع لعملية التحقّق العادية من فتح قفل الجهاز، وعندها لن يحصل المستخدم إلا على الوعد الذي تم إرجاعه من خلال .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" ...>

يمكنك التعرّف على كيفية تقديم تجربة المستخدم هذه في مقالة تسجيل الدخول باستخدام مفتاح مرور من خلال ميزة الملء التلقائي للنموذج، وكذلك تنفيذ مفاتيح المرور باستخدام ميزة الملء التلقائي للنموذج في تطبيق الويب.

إعادة المصادقة

في بعض الحالات، مثل استخدام مفاتيح المرور لإعادة المصادقة، يكون معرِّف المستخدم معروفًا. في هذه الحالة، نريد استخدام مفتاح مرور بدون أن يعرض المتصفّح أو نظام التشغيل أي شكل من أشكال أداة اختيار الحساب. ويمكن تحقيق ذلك من خلال ضبط قائمة بمعرّفات بيانات الاعتماد في المعلَمة allowCredentials.

وفي هذه الحالة، إذا كانت أي من بيانات الاعتماد المُسمّاة متاحة على الجهاز، سيُطلَب من المستخدم فتح قفل الجهاز على الفور. وإذا لم يكن الأمر كذلك، سيُطلب من المستخدم تقديم جهاز آخر (هاتف أو مفتاح أمان) يحتوي على بيانات اعتماد صالحة.

لتحقيق تجربة المستخدم هذه، عليك تقديم قائمة بأرقام تعريف بيانات الاعتماد الخاصة بالمستخدم الذي يسجّل الدخول. يجب أن يتمكن الجهة المحظورة من الاستعلام عنها لأن المستخدم معروف بالفعل. تقديم أرقام تعريف بيانات الاعتماد كعناصر 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: رقم تعريف لبيانات اعتماد المفتاح العام التي حصل عليها الجهة المحظورة عند تسجيل مفتاح المرور.
  • type: عادةً ما يكون هذا الحقل 'public-key'.
  • transports: تشير هذه السمة إلى وسائل النقل التي يستخدمها الجهاز الذي يحمل بيانات الاعتماد هذه من أجل تحسين واجهة المستخدم التي تطلب من المستخدم مشاركة عرض جهاز خارجي. يجب أن تتضمّن هذه القائمة، في حال توفّرها، نتيجة طلب getTransports() أثناء تسجيل كل بيانات اعتماد.

ملخّص

إنّ بيانات الاعتماد القابلة للاكتشاف تجعل تجربة تسجيل الدخول باستخدام مفتاح المرور أكثر سهولة من خلال السماح للمستخدمين بتخطّي إدخال اسم المستخدم. من خلال الجمع بين residentKey وrequireResidentKey وallowCredentials، يمكن للجهات المحظورة توفير تجارب تسجيل الدخول التي:

  • إظهار أداة اختيار الحساب المشروط
  • إظهار نموذج مفتاح مرور تلقائيًا
  • إعادة المصادقة

استخدام بيانات الاعتماد القابلة للاكتشاف بحكمة: ومن خلال إجراء ذلك، يمكنك تصميم تجارب متطورة لتسجيل الدخول باستخدام مفتاح مرور، سيكون المستخدمون أكثر سلاسةً ويزداد احتمال تفاعلهم معها.