> ## Content Index
> Fetch the complete content index at: https://arabroot.io/llms.txt
> Use this file to discover other available public pages before exploring further.

# الدخول دون كلمة مرور: شرح Passkeys وWebAuthn
- URL: https://arabroot.io/articles/الدخول-دون-كلمة-مرور-passkeys-و-fido2/
- Published: 2026-10-05T09:30:00.000Z
- Updated: 2026-10-09T09:42:00.000Z
- Description: لماذا لا تحميك رموز SMS وTOTP من التصيد الحديث، وكيف تحل Passkeys المشكلة بمفتاح خاص لا يغادر جهازك.
- Author: فريق عرب رووت
- Tags: الأدلة التقنية, الأمن السيبراني, الاستضافة الذاتية

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

والحل الذي اتفقت عليه Apple وGoogle وMicrosoft ومعهم بقية الصناعة هو أن نلغي السر المشترك من الأساس، فيحمل جهاز المستخدم مفتاحاً خاصاً لا يغادره، ولا يحفظ السيرفر إلا المفتاح العام المقابل له، وهذا ما تسمعه اليوم باسم **الدخول دون كلمة مرور Passwordless** أو **Passkeys**، والمعايير التي تقوم عليها اسمها FIDO2 وWebAuthn. وهذا المقال جزء من مرحلة الدخول الموحد SSO في خارطة الطريق، فإذا لم تقرأ [شرح OAuth وOpenID Connect للمبتدئين](https://arabroot.io/articles/%D8%B4%D8%B1%D8%AD-oauth-%D9%88-openid-connect-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/) بعد فلا بأس، ولكنك سوف تحتاجه في الجزء الذي نربط فيه Passkeys بمزود الهوية. وسوف نناقش في هذا المقال ما يلي:

- المشكلة في كلمات المرور، ولماذا لا تحمي رسائل SMS ورموز TOTP من التصيد Phishing الحديث.
- الفكرة: التوقيع بالمفتاح الخاص Private Key بدلاً من السر المشترك، وربط المفتاح بالموقع Origin Binding.
- الأسماء التي تختلط على الجميع: FIDO Alliance وU2F وFIDO2 وWebAuthn وCTAP2 وPasskeys.
- التسجيل Registration والدخول Authentication خطوة خطوة، ولماذا لا يحصل الموقع المزيف على شيء.
- تجربة عملية صغيرة نرى فيها البيانات الحقيقية التي تمر بين المتصفح والسيرفر.
- Passkey متزامن أم مفتاح أمان Security Key، والاسترجاع عند ضياع الجهاز، والدخول من جهاز آخر بالهاتف.
- مفاتيح الأمان مثل YubiKey وبدائلها: ما تستخدم له غير الدخول، والطرازات المتوفرة، وما تنتبه له عند الشراء.
- Passkeys في الأدوات التي تستضيفها بنفسك: authentik وKeycloak وVaultwarden وNextcloud وGitea، ومفاتيح SSH من نوع FIDO2.
- خطة الانتقال في مؤسستك، والأخطاء الشائعة، ومقارنة طرق الدخول في جدول واحد.

## ما المشكلة في كلمات المرور؟

لنبدأ بالطريقة التي يعمل بها كل نظام تقريباً: يختار المستخدم كلمة مرور، ويحفظ السيرفر نسخة منها بعد الـ Hashing، وعند الدخول يكتبها المستخدم فيحسب السيرفر الـ Hash ويقارنه. والمشكلة أن هذه الطريقة تفشل من ثلاثة أبواب، كل باب منها مستقل عن الآخر:

1. **إعادة الاستخدام Password Reuse:** أغلب المستخدمين يستخدمون الكلمة نفسها في أكثر من موقع، فإذا تسربت من منتدى قديم جرب المهاجم الزوج نفسه، أي البريد وكلمة المرور، على البريد وVPN الشركة وكل خدمة معروفة، وهذا ما يسمى حشو بيانات الدخول Credential Stuffing، وهو يعمل آلياً على ملايين الحسابات.
2. **التصيد Phishing:** رسالة تقود المستخدم إلى صفحة تشبه صفحة شركته تماماً على نطاق قريب من نطاقها، فيكتب كلمة المرور بنفسه ويسلمها للمهاجم. ولاحظ أن الكلمة هنا قد تكون طويلة وفريدة وقوية، ولكن قوتها لا تفيد شيئاً، لأن المستخدم هو الذي كتبها في المكان الخطأ.
3. **تسرب قاعدة البيانات Data Breach:** إذا سرقت قاعدة بيانات السيرفر فالمهاجم يملك الـ Hash لكل مستخدم، ويستطيع أن يجرب عليه ملايين الكلمات في الثانية على بطاقات GPU دون أي حد لعدد المحاولات، فتسقط الكلمات الضعيفة أولاً ثم تعود إلى الباب الأول فتجرب على مواقع أخرى. والـ Salt وخوارزميات مثل Argon2 تبطئ هذا الكسر كثيراً، ولكنها لا تمنعه عن الكلمات السهلة.

![مخطط من ثلاثة أجزاء: مستخدم يكرر كلمة المرور نفسها في منتدى وبريد وVPN فيتسرب المنتدى ويجرب المهاجم الكلمة على البقية، ومستخدم يكتب كلمة المرور ورمز التحقق في صفحة مزيفة ينقلها وسيط المهاجم إلى الموقع الحقيقي فيسرق الجلسة، وقاعدة بيانات مسروقة تكسر كلماتها دون اتصال على GPU](https://arabroot.io/content/images/2026/10/passkeys-01-password-problems.webp)

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

وهذه ليست مخاطر نظرية، ففي [تقرير Verizon لتحقيقات اختراق البيانات DBIR لعام 2026](https://www.verizon.com/business/resources/reports/dbir/?ref=arabroot.io) كان استخدام بيانات الدخول المسروقة Use of Stolen Credentials حاضراً في 36% من الاختراقات التي حللها التقرير، وإذا حسبت إساءة استخدام بيانات الدخول Credential Abuse في أي مرحلة من مراحل الاختراق فهي في المرتبة الأولى بنسبة 39%. وصحيح أن نسبتها كنقطة الدخول الأولى انخفضت إلى 13% بعد أن تقدم عليها استغلال الثغرات، ولكن التقرير نفسه يوضح أن جزءاً من هذا الانخفاض سببه أنه أضاف الانتحال Pretexting إلى القائمة هذا العام، وبالتالي فالحسابات المسروقة ما زالت من أكثر ما يعتمد عليه المهاجمون.

### أضفنا رمز SMS ثم TOTP، فلماذا ما زال التصيد ينجح؟

الحل الأول الذي يخطر على البال هو المصادقة متعددة العوامل Multi-Factor Authentication، واختصاراً MFA، فنطلب مع كلمة المرور شيئاً آخر يملكه المستخدم، وأشهر صوره ثلاث:

- **رمز عبر SMS:** يرسل السيرفر رمزاً من ست خانات إلى رقم الجوال. وهو أفضل من كلمة المرور وحدها، ولكن الرقم يمكن أن ينقل إلى شريحة أخرى بخداع شركة الاتصالات SIM Swapping، والرسالة نفسها تمر عبر شبكة الهاتف دون تشفير بين الطرفين، لذلك صنفت [إرشادات NIST SP 800-63B-4](https://pages.nist.gov/800-63-4/sp800-63b.html?ref=arabroot.io) الرسائل والمكالمات عبر شبكة الهاتف على أنها طريقة مقيدة Restricted.
- **رمز TOTP من تطبيق المصادقة:** مثل الذي شرحنا فرضه في [دليل authentik](https://arabroot.io/articles/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-authentik-%D9%84%D9%84%D8%AF%D8%AE%D9%88%D9%84-%D8%A7%D9%84%D9%85%D9%88%D8%AD%D8%AF/#mfa)، ويولده التطبيق كل 30 ثانية من سر مشترك بينه وبين السيرفر. وهو يحل مشكلة SIM Swapping، ولكنه ما زال سراً مشتركاً، أي أن السيرفر يحفظ نسخة من السر نفسه.
- **الموافقة من الهاتف Push Approval:** يظهر للمستخدم إشعار «هل تحاول الدخول؟» فيضغط موافق. وهو مريح، ولكن المهاجم الذي يملك كلمة المرور يستطيع أن يرسل إشعاراً بعد إشعار حتى يضغط المستخدم موافق ليتخلص منها، وهذا ما يسمى إرهاق الموافقة MFA Fatigue.

والمشكلة المشتركة بين الثلاث هي أن المستخدم يستطيع أن ينقل الرمز أو الموافقة إلى المهاجم، فالرمز المكون من ست خانات لا يعرف أين كتب، والسيرفر لا يعرف من أين جاء. وهذا ما تستغله هجمات التصيد عبر وسيط Adversary-in-the-Middle، واختصاراً AiTM، حيث يضع المهاجم بين المستخدم والموقع الحقيقي سيرفراً يعمل كـ Reverse Proxy، فيرى المستخدم الصفحة الحقيقية نفسها لأنها تمر عبر الوسيط، ويكتب كلمة المرور ثم رمز TOTP، فينقلهما الوسيط إلى الموقع الحقيقي في الثانية نفسها، ثم يأخذ ملف تعريف الجلسة Session Cookie الذي يعود من الموقع ويستخدمه المهاجم كأنه المستخدم. وهذه الهجمات لم تعد تحتاج خبرة كبيرة، فهناك أدوات مفتوحة المصدر جاهزة لهذا الغرض، وقد وثقت Microsoft في يوليو 2022 [حملة واحدة من هذا النوع](https://www.microsoft.com/en-us/security/blog/2022/07/12/from-cookie-theft-to-bec-attackers-use-aitm-phishing-sites-as-entry-point-to-further-financial-fraud/?ref=arabroot.io) استهدفت أكثر من 10,000 مؤسسة منذ سبتمبر 2021، وكانت النصيحة في نهاية التقرير استخدام MFA مقاوم للتصيد Phishing-Resistant يعتمد على FIDO2.

ولهذا السبب تنص إرشادات NIST صراحة على أن كلمات المرور ورموز OTP والمصادقة عبر قناة ثانية Out-of-Band ليست مقاومة للتصيد، وتشترط على السيرفر في المستوى AAL2 أن يقدم لمستخدميه خياراً واحداً على الأقل مقاوماً للتصيد، وتشترط في المستوى الأعلى AAL3 مقاومة التصيد مع مفتاح خاص لا يمكن إخراجه من الجهاز. والسؤال الآن: كيف يكون الدخول مقاوماً للتصيد أصلاً؟

## الفكرة: مفتاح خاص لا يغادر جهازك

الحل يأتي من التشفير بالمفتاح العام Public-Key Cryptography، والفكرة أن لكل مستخدم زوجاً من المفاتيح: مفتاح خاص Private Key يبقى في جهازه ولا يخرج منه، ومفتاح عام Public Key يعطيه للسيرفر. وما يوقعه المفتاح الخاص يستطيع أي شخص يملك المفتاح العام أن يتأكد من صحته، ولكنه لا يستطيع أن يوقع مثله. وأقرب تشبيه لذلك هو الختم الرسمي، فالختم نفسه في درجك وحدك، وكل جهة لديها صورة من شكله تستطيع أن تتأكد أن الورقة مختومة بختمك، ولكن صورة الختم لا تختم شيئاً.

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

![مخطط يبين جهاز المستخدم وفيه المفتاح الخاص داخل شريحة آمنة يفتح بالبصمة، والسيرفر وفيه جدول المستخدمين بالمفاتيح العامة فقط، والسيرفر يرسل قيمة عشوائية فيوقعها الجهاز ويتحقق السيرفر من التوقيع بالمفتاح العام](https://arabroot.io/content/images/2026/10/passkeys-02-key-pair.webp)

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

ولاحظ ما الذي تغير في الأبواب الثلاثة التي ذكرناها:

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

وقد يتساءل البعض: أليست هذه فكرة مفاتيح SSH نفسها؟ والإجابة نعم، فعندما تدخل إلى السيرفر بمفتاح `ed25519` كما في [تأمين خادم VPS من أول دخول](https://arabroot.io/articles/%D8%AA%D8%A3%D9%85%D9%8A%D9%86-%D8%AE%D8%A7%D8%AF%D9%85-vps-%D9%85%D9%86-%D8%A3%D9%88%D9%84-%D8%AF%D8%AE%D9%88%D9%84/#ssh-key) فأنت تفعل الشيء نفسه، فالمفتاح الخاص على جهازك والعام في ملف `authorized_keys` على السيرفر. والفرق أن Passkeys تنقل هذه الفكرة إلى المتصفح وإلى كل المستخدمين، وتضيف إليها ما ينقص SSH في عالم الويب: الربط بالنطاق، والتحقق من المستخدم ببصمة أو PIN، وحفظ المفتاح في شريحة آمنة بدلاً من ملف على القرص.

## FIDO2 وWebAuthn وPasskeys: ما الفرق بين هذه الأسماء؟

هذه الأسماء تستخدم أحياناً كأنها شيء واحد، وهي في الحقيقة طبقات فوق بعضها، وفيما يلي كل اسم وأين مكانه:

- **FIDO Alliance:** تحالف من الشركات يضع معايير الدخول دون كلمات مرور، واسمه اختصار Fast IDentity Online.
- **U2F:** المعيار الأقدم من FIDO، وكان مفتاح الأمان فيه عاملاً ثانياً فقط بعد كلمة المرور. وبروتوكوله بين الجهاز والمفتاح يسمى اليوم CTAP1، كما تنص عليه [مواصفة CTAP](https://fidoalliance.org/specs/fido-v2.2-ps-20250714/fido-client-to-authenticator-protocol-v2.2-ps-20250714.html?ref=arabroot.io) نفسها.
- **FIDO2:** الاسم الذي يجمع معيارين، وهما WebAuthn وCTAP2، ومعهما أصبح المفتاح قادراً على أن يكون وسيلة الدخول الوحيدة، أي دون كلمة مرور.
- **WebAuthn:** واجهة برمجية Web API من W3C يستخدمها موقعك من JavaScript عبر الدالتين `navigator.credentials.create()` و`navigator.credentials.get()`. وقد أصبح [المستوى الأول](https://www.w3.org/TR/webauthn-1/?ref=arabroot.io) توصية رسمية W3C Recommendation في 4 مارس 2019، ثم [المستوى الثاني](https://www.w3.org/TR/webauthn-2/?ref=arabroot.io) في 8 أبريل 2021، ثم [المستوى الثالث](https://www.w3.org/TR/webauthn-3/?ref=arabroot.io) في 25 أغسطس 2026.
- **CTAP2:** البروتوكول Client to Authenticator Protocol الذي يتكلم به المتصفح أو نظام التشغيل مع المفتاح عبر USB أو NFC أو Bluetooth، وفي إصداره الأحدث طريقة الدخول من جهاز آخر بالهاتف التي نشرحها لاحقاً.
- **Passkey:** الاسم التجاري الذي اتفقت عليه الشركات لما يسمى في المواصفة Discoverable Credential، أي مفتاح يحفظ في الجهاز مع معرف المستخدم، فلا يحتاج الموقع أن يسألك عن اسم المستخدم أولاً. وفي [5 مايو 2022](https://fidoalliance.org/apple-google-and-microsoft-commit-to-expanded-support-for-fido-standard-to-accelerate-availability-of-passwordless-sign-ins/?ref=arabroot.io) أعلنت Apple وGoogle وMicrosoft التزامها بدعم مزامنة هذه المفاتيح بين أجهزة المستخدم واستخدامها من جهاز قريب أياً كان نظامه، وهذا ما جعل الاسم معروفاً للجميع.

وبعد الأسماء هناك مصطلحات سوف تقابلها في كل إعداد، وأهمها ما يلي:

| المصطلح                                            | معناه باختصار                                                                                                 |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| الطرف المعتمد Relying Party، واختصاراً RP          | الموقع أو التطبيق الذي تدخل إليه، ومعرفه rp.id هو النطاق، مثل bank.example                                    |
| المصادق Authenticator                              | الشيء الذي يحمل المفتاح الخاص ويوقع، سواء كان هاتفك أو حاسوبك أو مفتاح أمان                                   |
| مصادق المنصة Platform Authenticator                | مدمج في الجهاز نفسه: Windows Hello وTouch ID وFace ID وقفل شاشة Android                                       |
| مصادق متنقل Roaming Authenticator                  | جهاز منفصل تنقله بين الحواسيب، مثل مفاتيح الأمان عبر USB أو NFC، ويسمى في المواصفة Cross-Platform             |
| حضور المستخدم User Presence، واختصاراً UP          | إثبات أن إنساناً موجود، بلمسة على المفتاح مثلاً، دون معرفة من هو                                              |
| التحقق من المستخدم User Verification، واختصاراً UV | إثبات أن صاحب الجهاز هو الموجود، ببصمة أو وجه أو PIN، وهو ما يجعل المفتاح يقوم مقام عاملين                    |
| الشهادة Attestation                                | توقيع اختياري من الشركة المصنعة يثبت نوع المفتاح وطرازه، وتستخدمه المؤسسات التي تريد أن تقبل طرازات محددة فقط |

## كيف يسجل الموقع مفتاحك أول مرة؟

تسمى عملية التسجيل في المواصفة مراسم التسجيل Registration Ceremony، وهي تحدث مرة واحدة لكل موقع ولكل جهاز، والصورة التالية تبين خطواتها بالترتيب:

![مخطط تسلسلي بين المصادق والمتصفح والسيرفر من سبع خطوات: طلب إضافة Passkey، ثم خيارات فيها القيمة العشوائية ومعرف الموقع، ثم المتصفح يضيف النطاق، ثم المستخدم يتحقق بالبصمة وينشأ زوج مفاتيح جديد لهذا الموقع، ثم يعود المفتاح العام، ثم يرسله المتصفح للسيرفر، ثم يتحقق السيرفر ويحفظه](https://arabroot.io/content/images/2026/10/passkeys-03-registration.webp)

مراسم التسجيل: زوج مفاتيح جديد لموقع واحد، ولا يخرج من جهازك إلا المفتاح العام

1. يضغط المستخدم «إضافة Passkey» في صفحة إعدادات حسابه.
2. يرد السيرفر بالخيارات Options: قيمة عشوائية Challenge جديدة، ومعرف الموقع `rp.id`، ومعرف المستخدم `user.id`، والخوارزميات التي يقبلها، وهل يشترط التحقق من المستخدم.
3. يمرر المتصفح هذه الخيارات إلى المصادق، ويضيف إليها شيئاً لا يستطيع الموقع أن يزوره، وهو النطاق Origin الذي فتحت منه الصفحة فعلاً.
4. يطلب المصادق من المستخدم أن يتحقق ببصمة أو PIN، ثم ينشئ زوج مفاتيح جديداً خاصاً بهذا الموقع وحده، ويحفظ المفتاح الخاص عنده.
5. يعيد المصادق معرف المفتاح Credential ID والمفتاح العام، ومعهما بيانات المصادق Authenticator Data.
6. يرسل المتصفح كل ذلك إلى السيرفر مع `clientDataJSON`، وهو نص JSON يكتبه المتصفح ويضع فيه نوع العملية والقيمة العشوائية والنطاق.
7. يتحقق السيرفر من أن القيمة العشوائية هي التي أرسلها، وأن النطاق هو نطاقه، وأن Hash معرف الموقع داخل بيانات المصادق يطابق نطاقه، وأن علامتي UP وUV موجودتان، ثم يحفظ في قاعدة البيانات اسم المستخدم ومعرف المفتاح والمفتاح العام وعداد التوقيعات Sign Count.

وهذا كل ما يحفظه السيرفر، فلا توجد كلمة مرور ولا Hash ولا سر مشترك، ولو نشرت هذا الجدول كاملاً على الإنترنت لما استطاع أحد أن يدخل به إلى أي حساب.

## الدخول، ولماذا لا يحصل الموقع المزيف على شيء

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

![مخطط من جزأين: في الأعلى دخول عادي إلى bank.example حيث يرسل السيرفر القيمة العشوائية ويضيف المتصفح النطاق ويوقع المصادق ويتحقق السيرفر، وفي الأسفل صفحة مزيفة bank-login.example ينقل وسيطها القيمة العشوائية الحقيقية، فيرى المتصفح النطاق المزيف ولا يجد المصادق مفتاحاً له، ويرفض المتصفح طلب مفاتيح bank.example](https://arabroot.io/content/images/2026/10/passkeys-04-login-phishing.webp)

المتصفح يكتب النطاق الحقيقي في كل طلب، والمصادق لا يملك مفتاحاً للنطاق المزيف

لنفرض أن المهاجم جهز الصفحة `bank-login.example` ووضع خلفها وسيطاً ينقل كل شيء إلى `bank.example` كما في هجمات AiTM التي شرحناها، فما الذي يستطيع أن يفعله؟

- إذا طلبت الصفحة المزيفة توقيعاً لمعرف الموقع `bank.example` فالمتصفح يرفض الطلب مباشرة، والسبب أن معرف الموقع يجب أن يكون نطاق الصفحة نفسه أو نطاقاً أعلى منه، والنطاق المزيف ليس كذلك.
- وإذا طلبت توقيعاً لنطاقها هي فالمصادق لا يملك أي مفتاح لهذا النطاق، لأن المستخدم لم يسجل فيه أبداً، فلا يوقع شيئاً.
- وحتى لو كان هناك توقيع بطريقة ما، فالمتصفح يكتب النطاق الحقيقي الذي فتحت منه الصفحة داخل `clientDataJSON`، وهذا النص جزء مما يوقعه المصادق، فإذا وصل إلى السيرفر بنطاق غير نطاقه رفضه.

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

📌

في يوليو 2022 وصلت رسائل SMS إلى 76 موظفاً على الأقل في Cloudflare تقودهم إلى صفحة دخول مطابقة لصفحة Okta التي يستخدمونها، على النطاق `cloudflare-okta.com` الذي سجل قبل أقل من 40 دقيقة من بدء الحملة، وأدخل ثلاثة موظفين بيانات دخولهم فعلاً، وكانت الصفحة ترسل اسم المستخدم وكلمة المرور ورمز TOTP إلى المهاجم فور كتابتها ليستخدمها قبل أن تنتهي صلاحية الرمز. ولكن الهجوم فشل، والسبب كما [نشرت الشركة في مدونتها](https://blog.cloudflare.com/2022-07-sms-phishing-attacks/?ref=arabroot.io) أن Cloudflare لا تستخدم رموز TOTP، وإنما تعطي كل موظف مفتاح أمان FIDO2 مربوطاً بالموقع، فلم يجد المهاجم ما ينقله. وذكرت الشركة أن حملة بالخصائص نفسها أصابت Twilio في الفترة نفسها. والدرس أن الموظف سوف يخطئ يوماً ما مهما دربته، وأن الحماية التي لا تعتمد على انتباهه هي التي تصمد.

## تجربة عملية: البيانات الحقيقية بين المتصفح والسيرفر

حتى نرى ما سبق بأعيننا كتبنا سيرفراً صغيراً بـ Node.js دون أي مكتبة خارجية، يقوم بدور الطرف المعتمد Relying Party: يصدر القيمة العشوائية، ويتحقق من `clientDataJSON` ومن بيانات المصادق، ويحفظ المفتاح العام، ثم يتحقق من التوقيع عند الدخول. والكود التالي للتعلم فقط، ففي تطبيق حقيقي استخدم مكتبة معروفة لـ WebAuthn في لغتك، والسبب أن المواصفة فيها تفاصيل كثيرة لا يغطيها مثال قصير، مثل قراءة صيغة CBOR والتحقق من الشهادة Attestation. احفظ الملف باسم `server.mjs`:

```javascript
// lab-passkeys: a tiny WebAuthn relying party, for learning only (no dependencies).
//   node server.mjs      then open http://bank.localhost:20891/
import { createServer } from 'node:http';
import { randomBytes, createHash, verify } from 'node:crypto';

const PORT = 20891, RP_ID = 'bank.localhost', ORIGIN = `http://${RP_ID}:${PORT}`;
const b64u = (buf) => Buffer.from(buf).toString('base64url');
const sha256 = (data) => createHash('sha256').update(data).digest();
const users = new Map();          // username -> { id, credentials: [] }
const credentials = new Map();    // credential id -> { user, publicKey, signCount }
let pending = null;               // the last challenge we issued

function checkClientData(clientDataJSON, type) {
    const c = JSON.parse(Buffer.from(clientDataJSON, 'base64url'));
    if (c.type !== type) throw new Error(`wrong type ${c.type}`);
    if (c.challenge !== pending) throw new Error('challenge does not match');
    if (c.origin !== ORIGIN) throw new Error(`wrong origin ${c.origin}`);
    return c;
}
function checkAuthData(authenticatorData) {
    const a = Buffer.from(authenticatorData, 'base64url');
    if (!a.subarray(0, 32).equals(sha256(RP_ID))) throw new Error('rpIdHash does not match');
    const flags = a[32];
    return { up: !!(flags & 1), uv: !!(flags & 4), be: !!(flags & 8), bs: !!(flags & 16), signCount: a.readUInt32BE(33) };
}

const routes = {
    'POST /register/options': ({ username }) => {
        const user = users.get(username) || { id: b64u(randomBytes(16)), credentials: [] };
        users.set(username, user);
        pending = b64u(randomBytes(32));
        return { challenge: pending, rp: { id: RP_ID, name: 'Lab Bank' }, user: { id: user.id, name: username, displayName: username },
            pubKeyCredParams: [{ type: 'public-key', alg: -7 }], authenticatorSelection: { residentKey: 'required', userVerification: 'required' } };
    },
    'POST /register/verify': ({ username, id, clientDataJSON, authenticatorData, publicKey }) => {
        const client = checkClientData(clientDataJSON, 'webauthn.create'), auth = checkAuthData(authenticatorData);
        if (!auth.up || !auth.uv) throw new Error('user not present or not verified');
        credentials.set(id, { user: username, publicKey, signCount: auth.signCount });
        pending = null;
        return { ok: true, client, flags: auth, stored: { credentialId: id, user: username, publicKey, signCount: auth.signCount } };
    },
    'POST /login/options': () => { pending = b64u(randomBytes(32)); return { challenge: pending, rpId: RP_ID, userVerification: 'required' }; },
    'POST /login/verify': ({ id, clientDataJSON, authenticatorData, signature }) => {
        const cred = credentials.get(id);
        if (!cred) throw new Error('unknown credential');
        const client = checkClientData(clientDataJSON, 'webauthn.get'), auth = checkAuthData(authenticatorData);
        const signed = Buffer.concat([Buffer.from(authenticatorData, 'base64url'), sha256(Buffer.from(clientDataJSON, 'base64url'))]);
        const key = { key: Buffer.from(cred.publicKey, 'base64url'), format: 'der', type: 'spki' };
        if (!verify('sha256', signed, key, Buffer.from(signature, 'base64url'))) throw new Error('bad signature');
        if (auth.signCount !== 0 && auth.signCount <= cred.signCount) throw new Error('signCount went backwards: cloned authenticator?');
        cred.signCount = auth.signCount; pending = null;
        return { ok: true, user: cred.user, client, flags: auth };
    },
};

createServer(async (req, res) => {
    const host = (req.headers.host || '').split(':')[0];
    if (req.method === 'GET') {
        res.writeHead(200, { 'content-type': 'text/html; charset=utf-8' });
        return res.end(`<!doctype html><title>${host}</title><h1>${host}</h1>` + CLIENT);
    }
    let body = ''; for await (const c of req) body += c;
    const route = routes[`${req.method} ${req.url}`];
    try {
        const out = route(JSON.parse(body || '{}'));
        console.log(req.url, JSON.stringify(out, null, 2));
        res.writeHead(200, { 'content-type': 'application/json' }); res.end(JSON.stringify(out));
    } catch (e) {
        console.log(req.url, 'REJECTED:', e.message);
        res.writeHead(400, { 'content-type': 'application/json' }); res.end(JSON.stringify({ ok: false, error: e.message }));
    }
}).listen(PORT, '127.0.0.1', () => console.log(`listening on ${ORIGIN}`));

// The browser side: the same calls a real login page makes.
const CLIENT = `<script>
const b64u = (b) => btoa(String.fromCharCode(...new Uint8Array(b))).replace(/\\+/g,'-').replace(/\\//g,'_').replace(/=+$/,'');
const fromB64u = (s) => Uint8Array.from(atob(s.replace(/-/g,'+').replace(/_/g,'/')), c => c.charCodeAt(0));
const post = async (url, data) => (await fetch(url, { method: 'POST', body: JSON.stringify(data) })).json();

async function register(username) {
  const o = await post('/register/options', { username });
  const cred = await navigator.credentials.create({ publicKey: { ...o, challenge: fromB64u(o.challenge), user: { ...o.user, id: fromB64u(o.user.id) } } });
  return post('/register/verify', { username, id: cred.id, clientDataJSON: b64u(cred.response.clientDataJSON),
    authenticatorData: b64u(cred.response.getAuthenticatorData()), publicKey: b64u(cred.response.getPublicKey()) });
}
async function login(rpId) {
  const o = await post('/login/options', {});
  const cred = await navigator.credentials.get({ publicKey: { ...o, rpId: rpId || o.rpId, challenge: fromB64u(o.challenge) } });
  window.last = { id: cred.id, clientDataJSON: b64u(cred.response.clientDataJSON),
    authenticatorData: b64u(cred.response.authenticatorData), signature: b64u(cred.response.signature) };
  return post('/login/verify', window.last);
}
</script>`;
```

ثم شغله:

```bash
node server.mjs
```

والمخرج سوف يكون كما يلي:

```text
listening on http://bank.localhost:20891
```

في الإعداد أعلاه لاحظ التالي:

- السيرفر يستمع على `127.0.0.1` فقط، ونفتحه من المتصفح باسم `bank.localhost`، والسبب أن معرف الموقع في WebAuthn يجب أن يكون نطاقاً وليس عنوان IP، ومتصفح Chrome يوجه أي اسم ينتهي بـ `.localhost` إلى جهازك ويعامله كسياق آمن Secure Context، فلا نحتاج شهادة TLS للتجربة.
- الدالة `checkClientData` تتحقق من ثلاثة أشياء: نوع العملية، وأن القيمة العشوائية هي آخر قيمة أصدرها السيرفر، وأن النطاق `origin` هو نطاقنا بالضبط.
- الدالة `checkAuthData` تقرأ أول 32 بايت من بيانات المصادق، وهي Hash معرف الموقع `rpIdHash`، وتقارنها بـ Hash نطاقنا، ثم تقرأ البايت التالي وفيه العلامات Flags، ثم عداد التوقيعات.
- عند الدخول يتحقق السيرفر من التوقيع على بيانات المصادق متبوعة بـ SHA-256 لنص `clientDataJSON`، وهذا ما ينص عليه المعيار، أي أن النطاق والقيمة العشوائية داخلان في ما وقعه المصادق.
- استخدمنا `getPublicKey()` في المتصفح حتى نأخذ المفتاح العام بصيغة SPKI جاهزة لـ Node.js، وهي متاحة منذ المستوى الثاني من WebAuthn، والمكتبات الحقيقية تقرأه من `attestationObject`.

بعد ذلك افتح `http://bank.localhost:20891/` في Chrome، وإذا لم يكن لديك مفتاح أمان فافتح أدوات المطور DevTools ثم من **More tools** اختر **WebAuthn** وفعل **Enable virtual authenticator environment** وأضف مصادقاً افتراضياً بالبروتوكول `ctap2` مع دعم Resident Keys وUser Verification، وهذا المصادق الافتراضي هو ما استخدمناه في التجربة. ثم اكتب في Console:

```javascript
await register('sara')
```

والمخرج سوف يكون كما يلي:

```json
{
  "ok": true,
  "client": {
    "type": "webauthn.create",
    "challenge": "K7vA7M_08id7LDh1SfZPs8cNclVqVeMKVmiPsl8FDNQ",
    "origin": "http://bank.localhost:20891",
    "crossOrigin": false
  },
  "flags": {
    "up": true,
    "uv": true,
    "be": false,
    "bs": false,
    "signCount": 1
  },
  "stored": {
    "credentialId": "u9oL6b8VhMLHeocEtiP9nO2KF0vViJCd7hXwvEMn6-I",
    "user": "sara",
    "publicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEF48Vp8IozFPhgHG1Dz_VVrgv3Q1pSOUI2ELT7ILCd_2r7OAwDu7YDpD80SNHr4iAWWeQehNbvVPoI76KS0-ZqQ",
    "signCount": 1
  }
}
```

لاحظ أن `clientDataJSON` فيه النطاق الذي كتبه المتصفح بنفسه، وأن ما حفظه السيرفر في `stored` هو المفتاح العام فقط، وهو 91 بايت بصيغة SPKI لمفتاح من نوع P-256\. ولاحظ العلامتين `be` و`bs`، وهما اختصار Backup Eligible وBackup State، وقيمتهما `false` هنا لأن المصادق الافتراضي مرتبط بجهاز واحد، أما Passkey المتزامن عبر حساب Google أو Apple فتظهر فيه العلامتان `true`، وتستطيع المؤسسة أن تبني سياستها على هاتين العلامتين كما تذكر إرشادات NIST. والآن سجل الدخول:

```javascript
await login()
```

والمخرج سوف يكون كما يلي:

```json
{
  "ok": true,
  "user": "sara",
  "client": {
    "type": "webauthn.get",
    "challenge": "9c3AaiBLSue68Fe7m0fkBqNiLB3nHJNCzGNGjJxa4q8",
    "origin": "http://bank.localhost:20891",
    "crossOrigin": false
  },
  "flags": {
    "up": true,
    "uv": true,
    "be": false,
    "bs": false,
    "signCount": 2
  }
}
```

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

وقد يتساءل البعض: ماذا لو التقط المهاجم هذا الطلب الموقع كاملاً وأعاد إرساله؟ لنجرب ذلك، فالدالة `login` تحفظ آخر طلب في `window.last`:

```javascript
await post('/login/verify', window.last)
```

والمخرج سوف يكون كما يلي:

```json
{
  "ok": false,
  "error": "challenge does not match"
}
```

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

### والآن نفتح الصفحة نفسها من نطاق مزيف

السيرفر نفسه يرد على أي اسم، فلنفتح `http://bank-login.localhost:20891/` وهي نسخة طبق الأصل من الصفحة، والقيم العشوائية فيها تأتي من السيرفر الحقيقي كما يفعل وسيط التصيد. ونطلب أولاً توقيعاً لمعرف الموقع الحقيقي:

```javascript
await login('bank.localhost').catch(e => e.name + ': ' + e.message)
```

والمخرج سوف يكون كما يلي:

```text
SecurityError: The relying party ID is not a registrable domain suffix of, nor equal to the current domain. Subsequently, an attempt to fetch the .well-known/webauthn resource of the claimed RP ID failed.
```

رفض المتصفح الطلب قبل أن يصل إلى المصادق، لأن `bank.localhost` ليس نطاق الصفحة ولا نطاقاً أعلى منها. ويذكر الخطأ ملف `.well-known/webauthn`، وهو طريقة في المستوى الثالث يعلن بها موقع حقيقي أن نطاقات أخرى تابعة له مسموح لها باستخدام مفاتيحه، والمهاجم بالطبع لا يستطيع أن يضع هذا الملف على نطاق البنك. ثم نطلب توقيعاً لنطاق الصفحة المزيفة نفسها:

```javascript
await login('bank-login.localhost').catch(e => e.name + ': ' + e.message)
```

والمخرج سوف يكون كما يلي:

```text
NotAllowedError: The operation either timed out or was not allowed. See: https://www.w3.org/TR/webauthn-2/#sctn-privacy-considerations-client.
```

هنا وصل الطلب إلى المصادق، ولكنه لا يملك أي مفتاح للنطاق `bank-login.localhost` فلم يوقع شيئاً، والخطأ عام عن قصد ولا يقول «لا يوجد مفتاح»، والسبب أن المواصفة تمنع المتصفح من أن يخبر أي موقع بالمفاتيح الموجودة على جهازك. وفي الحالتين لم يحصل المهاجم على أي شيء ينقله إلى السيرفر الحقيقي. وعندما تنتهي أوقف السيرفر بـ Ctrl+C، ومن لوحة WebAuthn احذف المصادق الافتراضي.

## Passkey متزامن أم مفتاح أمان Security Key؟

بحسب [تعريف FIDO Alliance](https://fidoalliance.org/passkeys/?ref=arabroot.io) فالـ Passkey قد يحفظ في هاتفك أو حاسوبك أو في مفتاح أمان، وهو نوعان: **Passkey متزامن Synced Passkey** ينسخ بين أجهزتك عبر خدمة سحابية، و**Passkey مرتبط بجهاز Device-Bound Passkey** لا يغادر جهازاً واحداً أبداً، والفرق بينهما هو الفرق بين الراحة والتحكم:

![مقارنة بين Passkey متزامن ينسخ مشفراً عبر حساب سحابي إلى الهاتف والحاسوب والجهاز اللوحي، ومفتاح أمان مرتبط بجهاز واحد مع مفتاح أساسي ومفتاح احتياطي، وتحت كل منهما ما تكسبه وما يجب أن تخطط له](https://arabroot.io/content/images/2026/10/passkeys-05-synced-vs-bound.webp)

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

- **المتزامن:** يحفظه نظام التشغيل في حسابك لدى Apple أو Google أو Microsoft، أو مدير كلمات مرور مثل Bitwarden، وينسخ مشفراً بين الطرفين End-to-End Encryption إلى كل أجهزتك. فإذا ضاع هاتفك دخلت من حاسوبك، وإذا اشتريت هاتفاً جديداً وجدت مفاتيحك عليه بعد تسجيل الدخول إلى حسابك. ولكن حمايته أصبحت مربوطة بحماية ذلك الحساب السحابي، والمفتاح الخاص نفسه موجود في أكثر من جهاز، لذلك تنص [إرشادات NIST](https://pages.nist.gov/800-63-4/sp800-63b.html?ref=arabroot.io) على أنه مقبول في المستوى AAL2 وممنوع في المستوى AAL3 الذي يشترط مفتاحاً لا يمكن إخراجه.
- **المرتبط بجهاز:** وأوضح صوره مفتاح الأمان الذي تعلقه في سلسلة مفاتيحك، فالمفتاح الخاص ينشأ داخل شريحته ولا يخرج منها، لا لك ولا لأي برنامج خبيث على حاسوبك. وهو الخيار الأقوى، ولكن إذا ضاع ولم يكن لديك غيره فقد أغلقت الباب على نفسك.

ومن أشهر مفاتيح الأمان مفاتيح YubiKey من Yubico، وهناك مفاتيح مفتوحة المصدر لمن يهمه ذلك، مثل [Nitrokey 3](https://www.nitrokey.com/products/nitrokeys?ref=arabroot.io) التي تنص الشركة على أن تصميمها وبرنامجها الداخلي Firmware مفتوحان المصدر، و[Solo 2 من SoloKeys](https://github.com/solokeys/solo2?ref=arabroot.io) التي ينشر مستودعها البرنامج الداخلي برخصتي Apache 2.0 وMIT وتصميم العتاد برخصة CERN-OHL-S. وسوف نعود إلى هذه المفاتيح، وما تستخدم له غير الدخول، وكيف تختار بينها، في [مفاتيح الأمان: YubiKey وبدائله](https://arabroot.io/articles/%D8%A7%D9%84%D8%AF%D8%AE%D9%88%D9%84-%D8%AF%D9%88%D9%86-%D9%83%D9%84%D9%85%D8%A9-%D9%85%D8%B1%D9%88%D8%B1-passkeys-%D9%88-fido2/#security-keys) بعد قليل.

### ماذا يحدث إذا ضاع الجهاز؟

هذا أول سؤال يسأله كل من يسمع عن Passkeys، والإجابة أن الاسترجاع يخطط له من يوم التسجيل وليس يوم الضياع، وفيما يلي القواعد التي نتبعها:

- **مفتاحان على الأقل لكل حساب مهم:** سجل مفتاحين في كل حساب، الأول معك والثاني في مكان آمن، أو Passkey متزامناً ومعه مفتاح أمان. والسبب أن المفتاح الثاني هو الذي يدخلك لتحذف الأول إذا ضاع.
- **أكواد الاسترجاع Recovery Codes:** أغلب الأنظمة تعطيك قائمة أكواد تستخدم مرة واحدة، فاطبعها واحفظها مع المفتاح الاحتياطي، ولا تحفظها في الجهاز نفسه.
- **الاسترجاع عبر الدعم الفني:** في المؤسسة يجب أن يكون هناك إجراء مكتوب لإعادة تفعيل حساب موظف فقد مفاتيحه، يتحقق فيه الدعم من هويته بطريقة لا يستطيع المهاجم أن يقلدها، والسبب أن المهاجم الذي لا يستطيع أن يتصيد المفتاح سوف يتصل بالدعم ويدعي أنه أضاعه.

### الدخول من جهاز آخر بهاتفك

لنفرض أنك على حاسوب جديد أو حاسوب في قاعة تدريب، ولا يوجد عليه أي Passkey، فهنا يأتي الدخول عبر جهاز آخر Cross-Device Authentication، ويسمى في مواصفة CTAP بالنقل الهجين Hybrid Transport. يعرض المتصفح رمز QR، فتمسحه بكاميرا هاتفك، ثم يتأكد الجهازان أنهما قريبان من بعضهما عبر Bluetooth، ثم يوقع الهاتف عبر نفق مشفر يمر بسيرفر وسيط Relay لا يرى إلا بيانات مشفرة، فيدخل الحاسوب دون أن ينتقل المفتاح الخاص إليه:

![مخطط يبين حاسوباً دون Passkey يعرض رمز QR، والهاتف يمسحه، ثم يتأكد الجهازان من قربهما عبر Bluetooth، ثم يوقع الهاتف عبر نفق مشفر يمر بسيرفر وسيط، فيصل التوقيع إلى متصفح الحاسوب ويدخل](https://arabroot.io/content/images/2026/10/passkeys-06-cross-device.webp)

الهاتف يوقع والحاسوب يدخل، والمفتاح الخاص لا يغادر الهاتف

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

## مفاتيح الأمان: YubiKey وبدائله

مر علينا مفتاح الأمان Security Key في هذا المقال أكثر من مرة، في قصة Cloudflare وفي المقارنة بين المتزامن والمرتبط بجهاز، وقد يتساءل البعض: ما هو هذا الجهاز بالضبط، وهل أحتاجه إذا كان هاتفي يحفظ Passkeys؟ مفتاح الأمان جهاز صغير بحجم مفتاح الباب، يتصل بالحاسوب عبر منفذ USB-A أو USB-C، وأغلب الطرازات تتصل بالهاتف لاسلكياً عبر NFC عندما تقربه منه، وفي داخله شريحة آمنة Secure Element تنشئ المفاتيح الخاصة وتحفظها ولا تسمح بإخراجها، فكل ما يخرج منها هو التوقيع. ولا يحتاج إلى بطارية ولا إلى شبكة، لأنه يأخذ الطاقة من المنفذ أو من مجال NFC. والفرق بينه وبين الهاتف أنه جهاز لا يفعل أي شيء آخر، فلا يوجد عليه متصفح ولا تطبيقات يصل منها برنامج خبيث إلى المفاتيح، ولا ينسخ محتواه إلى أي سحابة، لذلك هو ما تختاره المؤسسات لحسابات المديرين، وهو الذي يحقق شرط المفتاح الذي لا يمكن إخراجه في المستوى AAL3 الذي ذكرناه.

![مفتاح YubiKey أسود بمنفذ USB-A معلق في سلسلة مفاتيح بجانب مفاتيح أبواب، وبجانبه مفتاح YubiKey 5C NFC جديد بمنفذ USB-C في غلافه البلاستيكي](https://arabroot.io/content/images/2026/10/passkeys-08-yubikey-5c-nfc.webp)

مفتاح YubiKey بمنفذ USB-A في سلسلة المفاتيح، وبجانبه YubiKey 5C NFC بمنفذ USB-C في غلافه، والدائرة الذهبية هي مكان اللمس. الصورة: Daniel Aleksandersen، بترخيص [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/?ref=arabroot.io)، المصدر: [Wikimedia Commons](https://commons.wikimedia.org/wiki/File:YubiKey%5F5C%5FNFC.jpg?ref=arabroot.io) (تم تصغيرها وتحويلها إلى WebP).

### ماذا تستطيع أن تفعل بمفتاح أمان واحد؟

المفتاح ليس ميزة واحدة، وإنما مجموعة تطبيقات Applications داخل الشريحة نفسها، لكل تطبيق مساحته وإعداداته، وبعضها موجود في كل المفاتيح، وبعضها في الطرازات متعددة البروتوكولات Multi-Protocol فقط، والصورة التالية تبين ذلك:

![مخطط يبين مفتاح أمان في الوسط فيه ثلاثة تطبيقات: FIDO2 في كل الطرازات ويخرج منه الدخول بالـ Passkey والعامل الثاني ومفاتيح SSH وتوقيع Git Commits وفك تشفير القرص، وOATH في الطرازات متعددة البروتوكولات ويخرج منه رموز TOTP، وOpenPGP وPIV في الطرازات متعددة البروتوكولات فقط ويخرج منهما تشفير البريد والملفات والدخول بالبطاقة الذكية](https://arabroot.io/content/images/2026/10/passkeys-09-security-key-uses.webp)

تطبيق FIDO2 موجود في كل مفتاح ويغطي أغلب الاستخدامات، أما الرموز والبطاقة الذكية ففي الطرازات متعددة البروتوكولات فقط

- **الدخول المقاوم للتصيد Phishing-Resistant Login:** وهو الاستخدام الأول، كعامل ثان Second Factor بعد كلمة المرور أو كـ Passkey كامل دون كلمة مرور، وابدأ بالحسابات التي إذا سقطت سقط معها كل شيء: مزود الهوية authentik أو Keycloak، والبريد الإلكتروني لأنه طريق استعادة كل الحسابات الأخرى، ومدير كلمات المرور Password Manager، ولوحة مزود السحابة، وحساب مسجل النطاق Domain Registrar ومزود DNS، والسبب في الأخير أن من يتحكم في سجلات DNS يستطيع أن يستقبل بريد نطاقك ويصدر شهادات باسمه. وفي [دليل تثبيت authentik](https://arabroot.io/articles/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-authentik-%D9%84%D9%84%D8%AF%D8%AE%D9%88%D9%84-%D8%A7%D9%84%D9%85%D9%88%D8%AD%D8%AF/#mfa) تسجل المفتاح من قائمة Enroll نفسها.
- **حفظ Passkeys داخل المفتاح:** عندما يطلب الموقع مفتاحاً من نوع Discoverable، ويسمى أيضاً Resident Key، يحفظ المفتاح اسم الموقع والحساب داخل الشريحة، وهذا يستهلك خانة Slot من مساحة محدودة، أما المفاتيح غير القابلة للاكتشاف Non-Discoverable التي تستخدم كعامل ثان فلا تستهلك أي مساحة وعددها غير محدود. والمساحة تختلف كثيراً بين الطرازات، فمفاتيح YubiKey ذات البرنامج الداخلي 5.7 وما بعده [تحفظ 100 Passkey](https://docs.yubico.com/hardware/yubikey/yk-tech-manual/yk5-apps-fido.html?ref=arabroot.io) وما قبلها 25 فقط، و[تنص Yubico](https://docs.yubico.com/hardware/yubikey/yk-tech-manual/yk5-firmware-overview.html?ref=arabroot.io) على أن البرنامج الداخلي لا يمكن تحديثه بعد التصنيع، لذلك تحقق من الرقم في صفحة الطراز قبل أن تشتري، ولا تعتمد على أنه سوف يزيد لاحقاً.
- **مفاتيح SSH:** النوعان `ed25519-sk` و`ecdsa-sk` اللذان شرحناهما في [مفاتيح SSH من نوع FIDO2](https://arabroot.io/articles/%D8%A7%D9%84%D8%AF%D8%AE%D9%88%D9%84-%D8%AF%D9%88%D9%86-%D9%83%D9%84%D9%85%D8%A9-%D9%85%D8%B1%D9%88%D8%B1-passkeys-%D9%88-fido2/#ssh-fido2) يعملان مع أي مفتاح FIDO2، وتضيف المفتاح العام إلى السيرفر كما في [تأمين خادم VPS من أول دخول](https://arabroot.io/articles/%D8%AA%D8%A3%D9%85%D9%8A%D9%86-%D8%AE%D8%A7%D8%AF%D9%85-vps-%D9%85%D9%86-%D8%A3%D9%88%D9%84-%D8%AF%D8%AE%D9%88%D9%84/#ssh-key).
- **توقيع Git Commits:** منذ [الإصدار 2.34 من Git](https://github.com/git/git/blob/master/Documentation/RelNotes/2.34.0.adoc?ref=arabroot.io) تستطيع أن توقع الـ Commits بمفتاح SSH بدلاً من GnuPG، وبالتالي يصبح مفتاح `ed25519-sk` نفسه مفتاح التوقيع، فتضبط `gpg.format` على القيمة `ssh` كما في [توثيق git config](https://git-scm.com/docs/git-config?ref=arabroot.io)، وتضع في `user.signingKey` مسار ملف المفتاح مثل `~/.ssh/id_ed25519_sk`، وتفعل `commit.gpgSign`، ومع كل Commit يطلب منك لمسة على المفتاح. وتذكر ملاحظات الإصدار نفسها أن `ssh-keygen` في OpenSSH 8.7 فيه خلل يمنع هذه الميزة، فاستخدم الإصدار 8.8 أو أحدث.
- **رموز TOTP:** الطرازات متعددة البروتوكولات فيها تطبيق OATH يحفظ أسرار رموز TOTP وHOTP داخل الشريحة بدلاً من الهاتف، ويعرض الرموز تطبيق الشركة مثل [Yubico Authenticator](https://www.yubico.com/products/yubico-authenticator/?ref=arabroot.io) عندما توصل المفتاح أو تقربه من الهاتف، والفائدة أن السر لا يسرق من الهاتف ولا يضيع معه. ولكن لاحظ أن الرمز الذي يظهر لك هو رمز TOTP عادي، تستطيع أن تكتبه في صفحة مزيفة فينقله الوسيط كما شرحنا في بداية المقال، لذلك استخدمه فقط للخدمات التي لا تدعم FIDO2.
- **OpenPGP والبطاقة الذكية PIV:** في الطرازات التي تدعمهما فقط، يعمل المفتاح كبطاقة ذكية Smart Card تحفظ مفاتيح GnuPG لتوقيع البريد والملفات وتشفيرها، أو شهادات PIV للدخول بالبطاقة الذكية، ومنها [الدخول إلى macOS](https://support.apple.com/guide/deployment/use-a-smart-card-on-mac-depc705651a9/web?ref=arabroot.io) الذي يدعم بطاقات PIV دون أي برنامج إضافي.
- **فك تشفير القرص في Linux:** إذا كان القرص مشفراً بـ LUKS2 فالأمر `systemd-cryptenroll --fido2-device=auto /dev/sda2` يضيف المفتاح كطريقة لفتحه، ثم تضيف `fido2-device=auto` إلى سطر القرص في `/etc/crypttab`، و[بحسب صفحة الدليل Man Page الخاصة بالأمر](https://man7.org/linux/man-pages/man1/systemd-cryptenroll.1.html?ref=arabroot.io) يجب أن يدعم المفتاح الامتداد `hmac-secret` الموجود في أغلب مفاتيح FIDO2\. وأبق كلمة المرور الأصلية في خانة أخرى من خانات LUKS، لأن ضياع المفتاح دونها يعني ضياع البيانات.
- **الدخول إلى Windows:** يستطيع الموظف أن يدخل إلى جهازه بمفتاح FIDO2، ولكن [بحسب توثيق Microsoft](https://learn.microsoft.com/en-us/entra/identity/authentication/howto-authentication-passwordless-security-key-windows?ref=arabroot.io) هذا يعمل في الأجهزة المرتبطة بـ Microsoft Entra ID أو المرتبطة بشكل هجين Hybrid Joined، ولا يعمل في الأجهزة المرتبطة بـ Active Directory المحلي وحده.

### الطرازات المتوفرة، وكيف تختار بينها

Yubico هي الأشهر، ولكنها ليست الوحيدة، وفيما يلي الطرازات التي تجدها غالباً، وكل رقم فيها من صفحات الشركات نفسها كما كانت في 6 أكتوبر 2026:

- [**YubiKey 5 Series**](https://www.yubico.com/products/yubikey-5-overview/?ref=arabroot.io)**:** المفتاح الكامل من Yubico، فيه FIDO2 وU2F وOTP وOATH وOpenPGP والبطاقة الذكية PIV، ومنافذه USB-A وUSB-C وNFC وLightning بحسب الطراز، فمثلاً [YubiKey 5C NFC](https://www.yubico.com/product/yubikey-5c-nfc/?ref=arabroot.io) فيه USB-C وNFC و100 خانة Passkeys.
- [**Security Key Series من Yubico**](https://www.yubico.com/store/security-key-series/?ref=arabroot.io)**:** FIDO فقط، أي FIDO2 وU2F دون OTP ولا OpenPGP ولا PIV، بمنفذ USB-A أو USB-C ومعه NFC، وهو أرخص من السلسلة 5 بنصف السعر تقريباً، و[صفحة Security Key C NFC](https://www.yubico.com/product/security-key-c-nfc-by-yubico-black/?ref=arabroot.io) تذكر 100 خانة Passkeys.
- [**YubiKey Bio**](https://www.yubico.com/product/yubikey-c-bio/?ref=arabroot.io)**:** فيه قارئ بصمة بدلاً من كتابة PIN على الحاسوب، وهو بنسختين: FIDO Edition فيها FIDO2 وU2F فقط، وMulti-protocol Edition تضيف PIV، و[بحسب توثيق Yubico](https://docs.yubico.com/hardware/yubikey/yk-tech-manual/yk5-bio-specifics.html?ref=arabroot.io) لا يوجد فيه NFC.
- **Google Titan Security Key:** من Google بمنفذ USB-A أو USB-C ومع كل منهما NFC، و[أعلنت Google في نوفمبر 2023](https://blog.google/innovation-and-ai/technology/safety-security/titan-security-key-google-store/?ref=arabroot.io) أن الطرازات الجديدة تحفظ أكثر من 250 Passkey.
- **Feitian:** شركة صينية لها [عدة عائلات](https://www.ftsafe.com/Products/FIDO?ref=arabroot.io)، منها ePass FIDO-NFC بمنفذ USB-A أو USB-C مع NFC، و[الطرازان K9D وK40+](https://www.ftsafe.com/Products/FIDO/NFC?ref=arabroot.io) فيهما أيضاً PIV وOpenPGP وHOTP وTOTP، وiePass بمنفذي Lightning وUSB-C معاً لأجهزة iPhone القديمة، وBioPass بالبصمة.
- **Token2:** شركة سويسرية، ومن طرازاتها [PIN+ Dual Release3.3](https://www.token2.com/shop/product/token2-t2f2-pin-dual-release2-fido2-u2f-and-totp-dual-port-nfc-security-key-with-pin-complexity-feature?ref=arabroot.io) الذي يجمع USB-A وUSB-C في جهاز واحد مع NFC، وفيه PIV وOpenPGP وTOTP، ويحفظ حتى 300 Passkey.
- **Nitrokey 3:** من شركة ألمانية، و[بحسب الأسئلة الشائعة في توثيقها](https://docs.nitrokey.com/nitrokeys/nitrokey3/faq?ref=arabroot.io) فهو مفتوح المصدر بالكامل في البرنامج الداخلي والعتاد، وفيه FIDO2 وOpenPGP وTOTP وPIV في Windows فقط، ويحفظ حتى 30 Passkey في طرازات NFC وحتى 100 في الطراز 3A Mini.
- **SoloKeys Solo 2:** مفتوح المصدر كما ذكرنا، و[في متجر الشركة](https://solokeys.com/?ref=arabroot.io) نسختان بمنفذ USB-A أو USB-C، الأولى Solo 2 دون NFC والثانية Solo 2+ معها NFC، ويذكر مستودعه دعم OATH وPIV وOpenPGP مع FIDO2.
- **OnlyKey:** يختلف عن البقية بلوحة أرقام على الجهاز نفسه تكتب فيها PIN بدلاً من لوحة المفاتيح، و[بحسب صفحة الشركة](https://onlykey.io/?ref=arabroot.io) فيه FIDO2 وU2F وOTP وTOTP وOpenPGP ومدير كلمات مرور، وبرنامجه الداخلي مفتوح المصدر، والطراز OnlyKey DUO فيه USB-A وUSB-C.

وفيما يلي الطرازات نفسها في جدول واحد:

| الطراز                      | خانات Passkeys في FIDO2                        | OpenPGP / PIV / OTP               | المنافذ                                         | البرنامج الداخلي مفتوح المصدر؟ | الأنسب لـ                                        |
| --------------------------- | ---------------------------------------------- | --------------------------------- | ----------------------------------------------- | ------------------------------ | ------------------------------------------------ |
| YubiKey 5 Series            | 100 مع البرنامج الداخلي 5.7 وما بعده، و25 قبله | الثلاثة                           | USB-A، USB-C، NFC، Lightning بحسب الطراز        | لا                             | المديرون، ومن يريد SSH وGnuPG وTOTP في جهاز واحد |
| Security Key Series         | 100                                            | لا يوجد، FIDO فقط                 | USB-A أو USB-C، مع NFC                          | لا                             | الموظفون والحسابات الشخصية بأقل تكلفة            |
| YubiKey Bio                 | 100 مع البرنامج الداخلي 5.7 وما بعده           | PIV في Multi-protocol Edition فقط | USB-A أو USB-C، دون NFC                         | لا                             | من يريد البصمة بدلاً من PIN على الحاسوب          |
| Google Titan Security Key   | أكثر من 250                                    | لا تذكر Google غير FIDO           | USB-A أو USB-C، مع NFC                          | لا تذكر Google ذلك             | حسابات Google والاستخدام الشخصي                  |
| Feitian ePass FIDO-NFC      | لا تذكر الشركة العدد                           | الثلاثة في K9D وK40+ فقط          | USB-A أو USB-C، مع NFC، وiePass بمنفذ Lightning | لا تذكر الشركة ذلك             | بديل متعدد البروتوكولات، وiPhone بمنفذ Lightning |
| Token2 PIN+ Dual Release3.3 | حتى 300                                        | الثلاثة                           | USB-A وUSB-C في جهاز واحد، مع NFC               | لا تذكر الشركة ذلك             | من لديه أجهزة بالمنفذين ويحتاج خانات كثيرة       |
| Nitrokey 3                  | 30 في طرازات NFC، و100 في 3A Mini              | الثلاثة، وPIV في Windows فقط      | USB-A أو USB-C، مع NFC، و3A Mini دون NFC        | نعم، مع العتاد                 | من يريد كوداً يستطيع مراجعته ويقبل خانات أقل     |
| SoloKeys Solo 2             | لا تذكرها الشركة                               | الثلاثة بحسب المستودع             | USB-A أو USB-C، وNFC في Solo 2+ فقط             | نعم، مع العتاد                 | المطورون، ومن يريد أن يبني برنامجه الداخلي بنفسه |
| OnlyKey                     | لا تذكرها الشركة                               | OpenPGP وOTP                      | USB-A، وDUO فيه USB-C أيضاً، دون NFC            | نعم                            | من يريد كتابة PIN على المفتاح نفسه               |

أما الأسعار فكانت في صفحات الشركات يوم 6 أكتوبر 2026 كما يلي: Security Key C NFC بـ 29 دولاراً، وYubiKey 5C NFC بـ 58 دولاراً، وYubiKey C Bio FIDO Edition بـ 98 دولاراً، وNitrokey 3 تبدأ من 54 يورو، وToken2 PIN+ Dual بـ 29.13 دولاراً، وSolo 2 بـ 35 دولاراً وSolo 2+ بـ 46 دولاراً. وهذه الأسعار تتغير، ولا تشمل الشحن والضرائب، فارجع إلى صفحة الطراز قبل أن تشتري.

### ما تنتبه له قبل الشراء وبعده

- **مفتاحان دائماً:** اشتر مفتاحين وسجلهما معاً في كل حساب كما ذكرنا في [ماذا يحدث إذا ضاع الجهاز؟](https://arabroot.io/articles/%D8%A7%D9%84%D8%AF%D8%AE%D9%88%D9%84-%D8%AF%D9%88%D9%86-%D9%83%D9%84%D9%85%D8%A9-%D9%85%D8%B1%D9%88%D8%B1-passkeys-%D9%88-fido2/#recovery)، والسبب أن مفاتيح الأمان لا تنسخ، فالمفتاح الاحتياطي الذي لم تسجله في حساب ما لن يدخلك إليه يوم يضيع الأول. لذلك عندما تضيف حساباً جديداً سجل المفتاحين في اليوم نفسه، واحتفظ بقائمة بسيطة بالحسابات المسجلة.
- **المنافذ حسب أجهزتك:** USB-C مع NFC يغطي أغلب الحواسيب الحديثة والهواتف، وإذا كانت عندك حواسيب قديمة بمنفذ USB-A فقط فاختر طرازاً بالمنفذين أو مفتاحاً لكل نوع.
- **شهادة FIDO:** ابحث عن الطراز في [قائمة المنتجات المعتمدة من FIDO Alliance](https://fidoalliance.org/certification/fido-certified-products/?ref=arabroot.io)، وتأكد أنه معتمد لـ FIDO2 وليس U2F فقط، ولاحظ مستوى الاعتماد Certification Level، فالمستوى L1 هو الأساسي، والمستويات الأعلى تختبر حماية المفتاح من هجمات أقوى، ومثال ذلك أن Yubico تذكر المستوى L2 لـ YubiKey 5C NFC.
- **PIN على المفتاح:** عين PIN لتطبيق FIDO2 من أول يوم، من تطبيق الشركة أو عند أول تسجيل، والسبب أن من يجد مفتاحك لا يستطيع أن يستخدمه دون PIN، وبعد عدد محدود من المحاولات الخاطئة يقفل التطبيق ولا يعود إلا بإعادة ضبط Reset تحذف كل Passkeys منه.
- **إذا ضاع مفتاح:** ادخل بالمفتاح الاحتياطي إلى كل خدمة واحذف المفتاح الضائع من قائمة مفاتيحها، وابدأ بمزود الهوية والبريد ومدير كلمات المرور، ثم اشتر بديلاً وسجله في الحسابات نفسها، وهنا تظهر فائدة القائمة التي احتفظت بها.
- **مكان المفتاح الاحتياطي:** احفظه في مكان آمن بعيد عن الأول، في البيت أو في خزنة، وليس في الحقيبة نفسها، لأن ما يضيع الأول غالباً يضيع الثاني معه، وضع معه أكواد الاسترجاع المطبوعة.
- **في المؤسسات:** اشتر بالجملة، فـ Yubico مثلاً تبيع علباً من 50 مفتاحاً، ووزع المفاتيح على المديرين أولاً بمفتاحين لكل واحد، وسجل الرقم التسلسلي Serial Number لكل مفتاح باسم صاحبه، ثم أكمل الخطة في [كيف تنقل مؤسستك إلى الدخول دون كلمة مرور؟](https://arabroot.io/articles/%D8%A7%D9%84%D8%AF%D8%AE%D9%88%D9%84-%D8%AF%D9%88%D9%86-%D9%83%D9%84%D9%85%D8%A9-%D9%85%D8%B1%D9%88%D8%B1-passkeys-%D9%88-fido2/#rollout). وتستطيع في authentik من إعداد Device type restrictions، وفي Microsoft Entra ID من قائمة AAGUID، أن تقصر التسجيل على الطرازات التي اشتريتها.

## Passkeys في الأدوات التي تستضيفها بنفسك

إذا كنت تدير خدماتك بنفسك فأغلب الأدوات الشائعة تدعم WebAuthn اليوم، وبعضها يدعم الدخول بـ Passkey دون كلمة مرور، وفيما يلي ما تحققنا منه في توثيق كل أداة:

- **authentik:** فيه خطوة اسمها [WebAuthn / FIDO2 / Passkeys authenticator setup stage](https://docs.goauthentik.io/add-secure-apps/flows-stages/stages/authenticator%5Fwebauthn/?ref=arabroot.io) لتسجيل مفاتيح الأمان والمصادقات المدمجة وPasskeys، ومن إعداداتها **Resident key requirement** الذي يجب أن يكون Preferred أو Required حتى يكون المفتاح Discoverable، و**User verification**، و**Authenticator Attachment** لتقصر التسجيل على المدمج أو المتنقل، و**Device type restrictions** لتقبل طرازات محددة فقط بناءً على بيانات FIDO Alliance. وللدخول دون كلمة مرور تبني تدفقاً فيه [خطوة Authenticator Validation](https://docs.goauthentik.io/add-secure-apps/flows-stages/stages/authenticator%5Fvalidate/?ref=arabroot.io) تسمح بفئة WebAuthn ثم خطوة User Login، ومنذ الإصدار 2025.12 تستطيع [خطوة Identification](https://docs.goauthentik.io/add-secure-apps/flows-stages/stages/identification/?ref=arabroot.io) أن تعرض Passkeys في قائمة الإكمال التلقائي Autofill للمتصفح. وفي [دليل تثبيت authentik](https://arabroot.io/articles/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-authentik-%D9%84%D9%84%D8%AF%D8%AE%D9%88%D9%84-%D8%A7%D9%84%D9%85%D9%88%D8%AD%D8%AF/#mfa) ستجد خيار WebAuthn device في قائمة Enroll نفسها التي سجلنا منها TOTP.
- **Keycloak:** كانت Passkeys فيه ميزة تجريبية Preview منذ الإصدار 23.0.0، ثم أصبحت [مدعومة رسمياً في الإصدار 26.4.0](https://www.keycloak.org/2025/09/passkeys-support-26-4?ref=arabroot.io) الذي صدر في سبتمبر 2025، وتفعل من **Authentication ← Policies ← Webauthn Passwordless Policy** دون تعديل تدفق الدخول الافتراضي، ومعها خطوة جديدة تتخطى العامل الثاني إذا دخل المستخدم بـ Passkey.
- **Vaultwarden:** وهو سيرفر متوافق مع تطبيقات Bitwarden، و[أضاف الإصدار 1.30.0](https://github.com/dani-garcia/vaultwarden/releases/tag/1.30.0?ref=arabroot.io) في نوفمبر 2023 حفظ Passkeys في الخزنة واستخدامها من إضافة المتصفح، وبحسب [توثيق Bitwarden](https://bitwarden.com/help/storing-passkeys/?ref=arabroot.io) فهي محمية بالتشفير بين الطرفين مثل بقية محتوى الخزنة، وتدخل في ملفات التصدير JSON. وهذا يجعلها Passkeys متزامنة على سيرفرك أنت بدلاً من حساب Apple أو Google.
- **Nextcloud:** الدخول بـ WebAuthn متاح افتراضياً ويستطيع المدير أن يعطله بالإعداد [auth.webauthn.enabled](https://docs.nextcloud.com/server/stable/admin%5Fmanual/configuration%5Fserver/config%5Fsample%5Fphp%5Fparameters.html?ref=arabroot.io)، ويذكر [دليل المستخدم](https://docs.nextcloud.com/server/stable/user%5Fmanual/en/user%5F2fa.html?ref=arabroot.io) مفاتيح FIDO2 ضمن الأجهزة التي تعمل للمصادقة الثنائية، وينبه إلى ألا تستخدم المفتاح نفسه للدخول وللعامل الثاني معاً، لأنك بذلك تعود إلى عامل واحد.
- **Gitea:** يدعم مفاتيح FIDO عبر WebAuthn [كعامل ثان](https://docs.gitea.com/usage/multi-factor-authentication?ref=arabroot.io) مع TOTP، ومنذ [الإصدار 1.23.0](https://blog.gitea.com/release-of-1.23.0/?ref=arabroot.io) الذي صدر في 24 ديسمبر 2024 تستطيع أن تدخل بالـ Passkey مباشرة من زر Sign in with a passkey.

### أين يوضع Passkey عندما يكون لديك SSO؟

عندما تتوفر Passkeys في كل تطبيق فالطريقة التي تخطر على البال هي أن يسجل كل موظف مفتاحه في Gitea ثم في Nextcloud ثم في كل تطبيق، وهذا الحل غير مناسب إطلاقاً لفريق، فكل موظف سوف يسجل مفتاحين في عشرة تطبيقات، وعندما يضيع مفتاح يجب حذفه من عشرة أماكن. والحل الأنسب هو أن يكون مزود الهوية Identity Provider، أي authentik أو Keycloak، هو المكان الوحيد الذي يستخدم فيه الموظف Passkey، ثم ينقل بروتوكول OpenID Connect هذا الدخول إلى كل التطبيقات كما شرحنا في [شرح OAuth وOpenID Connect](https://arabroot.io/articles/%D8%B4%D8%B1%D8%AD-oauth-%D9%88-openid-connect-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/):

![مخطط يبين المستخدم يوقع بالـ Passkey أو مفتاح الأمان عند مزود الهوية authentik أو Keycloak الذي يحفظ المفاتيح العامة، ثم يرسل مزود الهوية رموز OpenID Connect إلى Gitea وNextcloud وOutline وGrafana](https://arabroot.io/content/images/2026/10/passkeys-07-idp-sso.webp)

تسجل المفتاح مرة واحدة عند مزود الهوية، وكل التطبيقات تعتمد عليه عبر OIDC

وبهذا الشكل تحصل كل التطبيقات على حماية Passkeys حتى لو لم تكن تدعمها، لأنها لا ترى كلمة مرور أصلاً، وإنما ترى ID Token من مزود الهوية، كما فعلنا في [ربط Gitea مع authentik عبر OIDC](https://arabroot.io/articles/%D8%B1%D8%A8%D8%B7-gitea-%D9%85%D8%B9-authentik-%D8%B9%D8%A8%D8%B1-oidc/). ولاحظ أن هذا يجعل مزود الهوية أهم سيرفر عندك، فإذا كانت فيه طريقة دخول ضعيفة بديلة فهي باب لكل التطبيقات، لذلك تبدأ سياسة Passkeys منه.

### مفاتيح SSH من نوع FIDO2

وما دام مفتاح الأمان معك، فيمكنك أن تحمي به دخولك إلى السيرفرات أيضاً، فمنذ [الإصدار 8.2 من OpenSSH](https://www.openssh.org/txt/release-8.2?ref=arabroot.io) الذي صدر في 14 فبراير 2020 يوجد نوعان جديدان من المفاتيح هما `ecdsa-sk` و`ed25519-sk`، والمفتاح الخاص فيهما مقسوم إلى جزأين، جزء في ملف على القرص وجزء داخل مفتاح الأمان لا يمكن إخراجه، فمن يسرق الملف وحده لا يستفيد منه. وتنشئه كما تنشئ أي مفتاح SSH ولكن مع مفتاح الأمان متصلاً بالجهاز:

```bash
ssh-keygen -t ed25519-sk -C "admin@example.com"
```

وسوف يطلب منك أن تلمس المفتاح لتأكيد الإنشاء، ثم يتعامل مع الناتج كأي مفتاح، فتضيف الملف `.pub` إلى `authorized_keys` كما في [تأمين خادم VPS من أول دخول](https://arabroot.io/articles/%D8%AA%D8%A3%D9%85%D9%8A%D9%86-%D8%AE%D8%A7%D8%AF%D9%85-vps-%D9%85%D9%86-%D8%A3%D9%88%D9%84-%D8%AF%D8%AE%D9%88%D9%84/#ssh-key)، وفي كل دخول يطلب لمسة على المفتاح. ويجدر الإشارة هنا إلى ثلاث ملاحظات من ملاحظات الإصدار نفسها: كل مفاتيح FIDO تدعم `ecdsa-sk` ولكن دعم `ed25519-sk` أقل انتشاراً في العتاد، فإذا رفض مفتاحك `ed25519-sk` فاستخدم `-t ecdsa-sk`، والخيار `-O resident` يحفظ المفتاح داخل الجهاز نفسه فتستطيع أن تستخرجه على أي حاسوب بالأمر `ssh-keygen -K`، ونسخة OpenSSH على جهازك يجب أن تكون مبنية بدعم مفاتيح الأمان عبر مكتبة `libfido2`.

## كيف تنقل مؤسستك إلى الدخول دون كلمة مرور؟

الانتقال لا يحدث في يوم واحد، ومحاولة فرضه على الجميع مرة واحدة هي أسرع طريق إلى طوابير أمام الدعم الفني، والخطة التي نقترحها على مراحل:

1. **المديرون أولاً:** ابدأ بحسابات الصلاحيات العالية، مديري الأنظمة ومزود الهوية والسحابة والبريد، وأعط كل واحد منهم مفتاحي أمان، والسبب أن هذه الحسابات هي هدف المهاجم الأول، وأصحابها هم الأقدر على تجربة الإعداد وكتابة التعليمات لبقية الفريق.
2. **مزود الهوية قبل التطبيقات:** فعل خطوة WebAuthn في authentik أو سياسة Passkeys في Keycloak، واربط التطبيقات به عبر OIDC، وبالتالي يكون التغيير في مكان واحد.
3. **الموظفون بعد ذلك:** اسمح لهم بتسجيل Passkey متزامن على هواتفهم أو Windows Hello على حواسيبهم، فهو الأسهل ولا يحتاج شراء أي جهاز، وأعط مفاتيح الأمان لمن يتعامل مع بيانات حساسة.
4. **الاسترجاع قبل الفرض:** جهز أكواد الاسترجاع، وفي authentik هي Static Tokens، واكتب إجراء الدعم الفني لمن يفقد مفاتيحه، وجربه على حساب تجريبي قبل أن تحتاجه.
5. **إغلاق الأبواب الضعيفة:** بعد أن يسجل الجميع مفاتيحهم أزل SMS ثم TOTP تدريجياً من تدفق الدخول، وراجع روابط استعادة كلمة المرور بالبريد، لأنها طريق دخول بديل أيضاً.
6. **حسابات الطوارئ:** احتفظ بحساب أو حسابين للطوارئ Break-Glass Accounts بمفاتيح أمان محفوظة في خزنة، حتى لا تفقد الوصول إلى مزود الهوية نفسه إذا تعطل شيء في إعداده.

وعندما يغادر موظف، فتعطيل حسابه في مزود الهوية يغلق دخوله إلى كل التطبيقات في الحال، وإذا أردت أن تحذف حساباته من التطبيقات نفسها تلقائياً فهذا ما يقوم به SCIM الذي شرحناه في [ما هو SCIM؟](https://arabroot.io/articles/%D9%85%D8%A7-%D9%87%D9%88-scim-%D8%A7%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%AD%D8%B3%D8%A7%D8%A8%D8%A7%D8%AA-%D8%AA%D9%84%D9%82%D8%A7%D8%A6%D9%8A%D8%A7/).

🛑

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

## مقارنة طرق الدخول

وفيما يلي الطرق التي مررنا عليها في جدول واحد:

| الطريقة                             | مقاومة التصيد                                 | سهولة الاستخدام           | إذا ضاع الجهاز                           | ما يحفظه السيرفر          |
| ----------------------------------- | --------------------------------------------- | ------------------------- | ---------------------------------------- | ------------------------- |
| كلمة مرور فقط                       | لا توجد                                       | سهلة، حتى ينساها المستخدم | لا يوجد جهاز، وإنما نسيان وإعادة تعيين   | Hash يمكن كسره            |
| كلمة مرور مع رمز SMS                | ضعيفة، الرمز ينقل عبر الوسيط ويمكن سرقة الرقم | متوسطة                    | نقل الرقم إلى شريحة جديدة                | Hash ورقم الجوال          |
| كلمة مرور مع TOTP                   | ضعيفة، الرمز ينقل عبر الوسيط في ثوان          | متوسطة                    | أكواد الاسترجاع أو إعادة الربط عبر الدعم | Hash والسر المشترك للرموز |
| موافقة Push                         | ضعيفة، ومعرضة لإرهاق الموافقة                 | سهلة                      | إعادة ربط التطبيق                        | Hash وربط الجهاز          |
| Passkey متزامن                      | عالية، مربوط بالنطاق                          | الأسهل، بصمة أو وجه       | موجود على بقية أجهزتك                    | مفتاح عام فقط             |
| مفتاح أمان Security Key مثل YubiKey | الأعلى، مربوط بالنطاق ولا يمكن نسخه           | جيدة، يحتاج حمل المفتاح   | المفتاح الاحتياطي                        | مفتاح عام فقط             |

## الخلاصة

وصلنا لنهاية الموضوع، وأهم ما فيه:

- كلمات المرور تفشل من ثلاثة أبواب: إعادة الاستخدام والتصيد وتسرب قاعدة البيانات، ورموز SMS وTOTP والموافقة من الهاتف تحسنها ولكنها لا تقاوم التصيد عبر وسيط AiTM، لأن المستخدم نفسه ينقل الرمز.
- Passkeys تلغي السر المشترك، فالمفتاح الخاص في جهازك والسيرفر يحفظ المفتاح العام فقط، والدخول توقيع على قيمة عشوائية جديدة في كل مرة.
- المتصفح يكتب النطاق الحقيقي فيما يوقعه المصادق، والمفتاح مربوط بنطاقه، فلا تحصل الصفحة المزيفة على أي شيء، وهذا ما يجعلها مقاومة للتصيد دون الاعتماد على انتباه المستخدم.
- FIDO2 هو WebAuthn من W3C في المتصفح مع CTAP2 من FIDO بين الجهاز والمفتاح، وPasskey هو المفتاح من نوع Discoverable، متزامناً كان أو مرتبطاً بجهاز.
- المتزامن مريح ولا يضيع بضياع الهاتف، ومفتاح الأمان أقوى ولكنه يحتاج مفتاحاً احتياطياً، وفي الحالتين خطط للاسترجاع قبل أن تحتاجه.
- مفتاح الأمان مثل YubiKey أو Nitrokey يحمي أيضاً مفاتيح SSH وتوقيع Git Commits وفك تشفير القرص، وعند الشراء انظر إلى عدد خانات Passkeys والمنافذ والبروتوكولات التي تحتاجها، واشتر مفتاحين دائماً.
- في بيئتك المستضافة ذاتياً ضع Passkeys عند مزود الهوية، authentik أو Keycloak، ودع OIDC ينقل الدخول إلى بقية التطبيقات، وأغلق بعد ذلك طرق الدخول الضعيفة البديلة.

[![](https://arabroot.io/content/images/2026/10/oauth-oidc-cover-cover.webp)دليلشرح OAuth وOpenID Connect للمبتدئينلماذا لا يجب أن يعرف أي تطبيق كلمة مرورك، وكيف يحل OAuth ذلك بتوكنات محدودة، وكيف يضيف OpenID Connect الدخول الموحد.](https://arabroot.io/articles/%D8%B4%D8%B1%D8%AD-oauth-%D9%88-openid-connect-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/)[![](https://arabroot.io/content/images/2026/10/scim-cover-cover.webp)دليلما هو SCIM؟ إدارة حسابات الموظفين تلقائياً في كل تطبيقاتكالدخول الموحد SSO يمنع الموظف المغادر من الدخول لكن حساباته تبقى نشطة، وSCIM ينشئ الحسابات ويعطلها في كل تطبيق تلقائياً.](https://arabroot.io/articles/%D9%85%D8%A7-%D9%87%D9%88-scim-%D8%A7%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%AD%D8%B3%D8%A7%D8%A8%D8%A7%D8%AA-%D8%AA%D9%84%D9%82%D8%A7%D8%A6%D9%8A%D8%A7/)[![](https://arabroot.io/content/images/2026/10/authentik-cover-cover-1.webp)دليلتثبيت authentik للدخول الموحد SSO إلى تطبيقاتككيف تثبت authentik حتى يدخل كل موظف إلى تطبيقات الفريق بحساب واحد، مع فرض المصادقة الثنائية على الجميع.](https://arabroot.io/articles/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-authentik-%D9%84%D9%84%D8%AF%D8%AE%D9%88%D9%84-%D8%A7%D9%84%D9%85%D9%88%D8%AD%D8%AF/)[![](https://arabroot.io/content/images/2026/10/secure-vps-cover-cover-2.webp)دليلتأمين سيرفر VPS على Ubuntu من أول دخولقبل أن تثبت أي تطبيق على سيرفرك الجديد، هذه الخطوات تغلق أبرز الثغرات وأولها الدخول بمفتاح SSH بدل كلمة المرور.](https://arabroot.io/articles/%D8%AA%D8%A3%D9%85%D9%8A%D9%86-%D8%AE%D8%A7%D8%AF%D9%85-vps-%D9%85%D9%86-%D8%A3%D9%88%D9%84-%D8%AF%D8%AE%D9%88%D9%84/)

## سجل التحديثات

- أكتوبر 2026: كتابة المقال، وتنفيذ تجربة التسجيل والدخول بسيرفر Node.js 22 ومصادق افتراضي في Chrome 154.
- أكتوبر 2026: إضافة قسم «مفاتيح الأمان: YubiKey وبدائله»: ما يستخدم له المفتاح غير الدخول، وجدول بالطرازات من صفحات الشركات، وما تنتبه له عند الشراء، مع صورة ومخطط جديدين.