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