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

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

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

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

طريقة العمل

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

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

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

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

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

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

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

نقاط التوافق

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

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

  • 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 لمعالجة العنصر.

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

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

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

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

المراجع