إنشاء مفتاح مرور لتسجيل الدخول بدون كلمة مرور

تجعل مفاتيح المرور حسابات المستخدمين أكثر أمانًا وبساطة وسهولة في الاستخدام.

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

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

آلية العمل

يمكن أن يُطلب من المستخدم إنشاء مفتاح مرور في إحدى الحالات التالية:

  • عندما يسجّل المستخدم الدخول باستخدام كلمة مرور.
  • عندما يسجّل المستخدم الدخول باستخدام مفتاح مرور من جهاز آخر (أي أنّ قيمة authenticatorAttachment هي cross-platform).
  • في صفحة مخصّصة يمكن للمستخدمين من خلالها إدارة مفاتيح المرور.

لإنشاء مفتاح مرور، يجب استخدام WebAuthn API.

المكونات الأربعة لخطوات تسجيل مفتاح المرور هي:

  • الخلفية: خادم الخلفية الذي يحتفظ بقاعدة بيانات الحسابات التي تخزّن المفتاح العام والبيانات الوصفية الأخرى المتعلقة بمفتاح المرور.
  • الواجهة الأمامية: الواجهة الأمامية التي تتواصل مع المتصفح وترسل طلبات الجلب إلى الخلفية.
  • المتصفح: متصفّح المستخدم الذي يستخدم JavaScript.
  • Authenticator: برنامج المصادقة لدى المستخدم الذي ينشئ مفتاح المرور ويخزّنه قد يكون هذا على نفس الجهاز الذي يستخدمه المتصفح (على سبيل المثال، عند استخدام Windows Hello) أو على جهاز آخر، مثل الهاتف.
الرسم التخطيطي لتسجيل مفتاح المرور

في ما يلي خطوات إضافة مفتاح مرور جديد إلى حساب مستخدم حالي:

  1. يسجّل أحد المستخدمين الدخول إلى الموقع الإلكتروني.
  2. بعد تسجيل دخول المستخدم، يطلب إنشاء مفتاح مرور في الواجهة الأمامية، مثلاً من خلال الضغط على زر "إنشاء مفتاح مرور".
  3. تطلب الواجهة الأمامية معلومات من الخلفية لإنشاء مفتاح مرور، مثل معلومات المستخدم والتحدي ومعرّفات بيانات الاعتماد لاستبعادها.
  4. تطلب الواجهة الأمامية من "navigator.credentials.create()" إنشاء مفتاح مرور. تُرجع هذه المكالمة وعودًا.
  5. يتم إنشاء مفتاح مرور بعد أن يوافق المستخدم على استخدام قفل شاشة الجهاز. يتم حل المشكلة ويتم إرجاع بيانات اعتماد المفتاح العام إلى الواجهة الأمامية.
  6. ترسل الواجهة الأمامية بيانات اعتماد المفتاح العام إلى الخلفية وتخزِّن معرّف بيانات الاعتماد والمفتاح العام المرتبط بحساب المستخدم لإجراء عمليات المصادقة المستقبلية.

نقاط التوافق

يتوافق WebAuthn مع معظم المتصفِّحات، ولكن هناك فجوات صغيرة. يمكنك الرجوع إلى صفحة دعم الأجهزة - passwords.dev للتعرّف على مجموعة المتصفّحات وأنظمة التشغيل التي تتيح إنشاء مفتاح مرور.

إنشاء مفتاح مرور جديد

إليك طريقة عمل الواجهة الأمامية عند طلب إنشاء مفتاح مرور جديد.

رصد الميزات

قبل عرض الزر "إنشاء مفتاح مرور جديد"، تأكَّد مما يلي:

  • يتوافق المتصفّح مع WebAuthn.
  • يتوافق الجهاز مع أداة مصادقة النظام الأساسي (يمكن إنشاء مفتاح مرور والمصادقة عليه).
  • يتوافق المتصفّح مع واجهة مستخدم 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()" لإنشاء مفتاح مرور جديد. تعرض واجهة برمجة التطبيقات وعدًا، في انتظار تفاعل المستخدم مع عرض مربع حوار مشروط.

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: رقم تعريف الجهة المحظورة هو نطاق ويمكن للموقع الإلكتروني تحديد نطاقه أو لاحقة قابلة للتسجيل. على سبيل المثال، إذا كان أصل الجهة المحظورة هو https://login.example.com:1337، يمكن أن يكون رقم تعريف الجهة المحظورة إما login.example.com أو example.com. إذا تم تحديد رقم تعريف الجهة المحظورة على أنّه example.com، يمكن للمستخدم المصادقة على login.example.com أو على أي نطاقات فرعية على example.com.

  • rp.name: اسم الجهة المحظورة.

  • pubKeyCredParams: يحدد هذا الحقل خوارزميات المفتاح العام المتوافقة مع الجهة المحظورة. وننصحك بضبطه على [{alg: -7, type: "public-key"},{alg: -257, type: "public-key"}]. تحدّد هذه السمة إتاحة ECDSA مع P-256 وRSA PKCS#1، وأن دعم هذه السياسات يقدّم تغطية كاملة.

  • authenticatorSelection.authenticatorAttachment: يجب ضبط هذا الإعداد على "platform" إذا كان إنشاء مفتاح المرور هذا ترقية من كلمة مرور، مثلاً في عرض ترويجي بعد تسجيل الدخول. تشير السمة "platform" إلى أنّ الجهة المحظورة تحتاج إلى برنامج مصادقة للنظام الأساسي (برنامج مصادقة مضمّن في جهاز النظام الأساسي) لن يطلب منك إدخال مفتاح أمان USB، مثل مفتاح أمان USB. لدى المستخدم خيار أبسط لإنشاء مفتاح مرور.

  • authenticatorSelection.requireResidentKey: اضبط القيمة على "صحيح" المنطقي. تخزِّن بيانات الاعتماد القابلة للاكتشاف (مفتاح المقيم) معلومات المستخدم في مفتاح المرور وتسمح للمستخدمين باختيار الحساب عند المصادقة.

  • authenticatorSelection.userVerification: تشير إلى ما إذا كانت عملية التحقق من المستخدم باستخدام قفل شاشة الجهاز هي "required" أو "preferred" أو "discouraged". الإعداد التلقائي هو "preferred"، أي أنّ برنامج المصادقة قد يتخطّى عملية التحقق من المستخدم. اضبط السمة على "preferred" أو احذفها.

إرسال بيانات اعتماد المفتاح العام التي تم إرجاعها إلى الخلفية

بعد أن يوافق المستخدم على استخدام قفل شاشة الجهاز، يتم إنشاء مفتاح مرور ويتم الوعد بعرض عنصر PublicKeyCredential إلى الواجهة الأمامية.

قد يتم رفض الوعد لأسباب مختلفة. يمكنك معالجة هذه الأخطاء من خلال التحقّق من السمة name الخاصة بالعنصر Error:

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

يحتوي كائن بيانات اعتماد المفتاح العام على السمات التالية:

  • id: رقم تعريف Base64URL مرمّز لمفتاح المرور الذي تم إنشاؤه يساعد هذا المعرّف المتصفّح في تحديد ما إذا كان مفتاح المرور المطابق متوفّرًا في الجهاز عند المصادقة. يجب تخزين هذه القيمة في قاعدة البيانات في الخلفية.
  • rawId: نسخة ArrayBuffer من معرّف بيانات الاعتماد.
  • response.clientDataJSON: بيانات العميل بترميز ArrayBuffer.
  • response.attestationObject: كائن مصادقة مرمّز من ArrayBuffer. يحتوي هذا على معلومات مهمة مثل رقم تعريف الجهة المحظورة والعلامات والمفتاح العام.
  • authenticatorAttachment: يتم عرض "platform" عند إنشاء بيانات الاعتماد هذه على جهاز متوافق مع مفتاح المرور.
  • type: يتم ضبط هذا الحقل دائمًا على "public-key".

إذا استخدمت مكتبة لمعالجة كائن بيانات اعتماد المفتاح العام في الخلفية، ننصحك بإرسال الكائن بأكمله إلى الخلفية بعد ترميزه جزئيًا باستخدام base64url.

حفظ بيانات الاعتماد

عند استلام بيانات اعتماد المفتاح العام في الخلفية، مرِّرها إلى مكتبة FIDO لمعالجة الكائن.

يمكنك بعد ذلك تخزين المعلومات التي تم استردادها من بيانات الاعتماد في قاعدة البيانات لاستخدامها في المستقبل. تحتوي القائمة التالية على بعض السمات المعتادة التي يمكن حفظها:

  • معرّف بيانات الاعتماد (المفتاح الأساسي)
  • رقم تعريف المستخدم
  • المفتاح العام

تتضمن بيانات اعتماد المفتاح العام أيضًا المعلومات التالية التي قد ترغب في حفظها في قاعدة البيانات:

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

المراجِع