لتوفير مصادقة سلسة ومناسبة للسياق على مستوى نطاقات متعددة، غالبًا ما تدمج المؤسسات صفحات تسجيل الدخول في إطارات iframe. ومع ذلك، يؤدي تحميل سياقات المصادقة داخل إطارات تابعة لجهات خارجية إلى تعرُّض المستخدمين لتهديدات خطيرة، مثل النقر المخادع (إعادة توجيه واجهة المستخدم) وإنشاء بيانات اعتماد غير مصرّح به. للحدّ من هذه المخاطر، توقِف المتصفّحات WebAuthn في إطارات iframe من مصادر متعددة تلقائيًا. ويتطلّب رفع هذا الحظر بأمان اتّباع بروتوكولات الدفاع المتعمّق النشطة.
تحديد نماذج التهديدات
قبل تفعيل مفاتيح المرور (WebAuthn) داخل الإطارات الفرعية، يجب فهم سيناريوهات إساءة الاستخدام التي تحمي منها:
- التتبُّع باستخدام إدخال إطار iframe مخفي: ينشئ المهاجم طلب WebAuthn من نطاقه الخاص باستخدام إعلان أو أداة على موقع إلكتروني موثوق به، ويخدع المستخدمين ليسمحوا باستخدام مفتاح مرور بدون رؤية السياق. يؤدي ذلك إلى ربط هوية المستخدم بحساب يتحكّم فيه مهاجم من أجل جمع البيانات.
- التراكب المرئي وخطف النقرات (إعادة تصميم واجهة المستخدم): تعرض صفحة رئيسية ضارة إطار iframe غير مرئي للمصادقة باستخدام CSS العادي وتتراكب مع عنصر في واجهة المستخدم مزيّف لسرقة نقرة تؤدي إلى بدء إجراءات المصادقة. وقد يؤدي ذلك إلى اختطاف الجلسة أو اتّخاذ إجراءات غير مصرّح بها بالقوة إذا أكمل المستخدم الطلب عن غير قصد.
لمواجهة هذه التهديدات، اتّبِع أفضل الممارسات التالية:
بالنسبة إلى المستند ذي المستوى الأعلى (الإطار العلوي):
بالنسبة إلى المستند المضمّن (إطار iframe):
- تفعيل ملفات تعريف الارتباط الخارجية المقسّمة
- حماية نقطة النهاية باستخدام "سياسة أمان المحتوى"
- الثقة، ولكن مع التحقّق من جهة الخادم
بالنسبة إلى كلا المستندَين:
تفعيل التفويض باستخدام "سياسة الأذونات"
تحظر المتصفّحات تلقائيًا إمكانية الوصول إلى WebAuthn في إطارات iframe متعددة المصادر. Permissions Policy هي آلية موحّدة لمنصّة الويب تتيح لمستند من المستوى الأعلى تفويض هذه الإمكانات القوية بشكل صريح إلى مصادر محدّدة وموثوق بها تابعة لجهات خارجية.
رموز الميزات
تستخدم WebAuthn رمزين مميزين مختلفين:
publickey-credentials-get: يمنح هذا النطاق إذنًا لاستخدام مفتاح المرور في عمليات تسجيل الدخول (navigator.credentials.get()).publickey-credentials-create: يمنح هذا الإذن إمكانية تسجيل مفتاح المرور (navigator.credentials.create()).
متطلبات التفعيل
يتطلّب تفعيل هذه الإمكانات توافقًا بين استجابة الخادم الرئيسي وعلامات الترميز من جهة العميل:
- عنوان استجابة HTTP لسياسة الأذونات (الموقع الإلكتروني للخادم الرئيسي): يجب أن تحدّد الصفحة الرئيسية المصادر المسموح بها في عناوين استجابة HTTP باستخدام بنية الحقول المنظَّمة.
Permissions-Policy: publickey-credentials-get=(self "https://embedded-auth.example.com")
سياسة الأذونات: التوافق مع publickey-credentials-get:
سياسة الأذونات: التوافق مع publickey-credentials-create:
- سمة
allowفي HTML: في ترميز HTML، يجب أن يوضّح العنصر<iframe>أيضًا أنّه يتيح استخدام الميزة.
<iframe src="https://embedded-auth.example.com?nonce=deadbeef12345678&client=https%3A%2F%2Fembedded-auth.example.com" allow="publickey-credentials-get"></iframe>
التوافق مع iframe allow="publickey-credentials-get":
Browser Support
التوافق مع السمة allow="publickey-credentials-create" في إطار iframe:
Browser Support
تفعيل ملفات تعريف الارتباط المجزّأة التابعة لجهات خارجية
لضمان سير عملية المصادقة بشكل موثوق، يجب إنشاء جلسة والحفاظ عليها ضمن إطار iframe المضمّن المشترك المصدر. مع انتقال المتصفّحات الحديثة إلى فرض قيود صارمة على ملفات تعريف الارتباط التابعة لجهات خارجية، يتم غالبًا حظر آليات الثبات العادية تلقائيًا، وقد تتطلّب هذه الآليات استدعاء Storage Access API للوصول إليها.
للتغلّب على هذه العقبات، اضبط ملفات تعريف الارتباط الخاصة بالجلسة باستخدام السمات SameSite:
None وSecure وPartitioned. تضمن آلية المنصة الموحّدة هذه الحفاظ على الحالة داخل إطار iframe مع احترام عناصر التحكّم في الخصوصية على مستوى المتصفّح.
المجموعة SameSite: None
تضع السمة SameSite:
None علامة صريحة على ملف تعريف الارتباط للسماح بالوصول إليه من مواقع إلكترونية متعددة، ما يتيح إرساله مع الطلبات التي يتم إجراؤها من سياق تابع لجهة خارجية (مثل iframe). هذه السمة شرط أساسي لكي تعمل ملفات تعريف الارتباط في سيناريوهات المصادر المتعدّدة، ولكن يجب دمجها مع السمة Secure لكي تقبلها المتصفّحات الحديثة.
المجموعة Partitioned
تتيح السمة Partitioned إمكانية استخدام ملف تعريف الارتباط في ملفات تعريف الارتباط في الحالة المقسَّمة المنفصلة (CHIPS)، ما يتيح تخزين ملف تعريف الارتباط بشكل منفصل لكل موقع إلكتروني من المستوى الأعلى. يضمن ذلك أن يظل ملف تعريف الارتباط متاحًا ضمن سياق إطار iframe المحدّد التابع لجهة خارجية، ما يتيح الحفاظ على حالة الجلسة بدون تفعيل تتبُّع إجراءات المستخدم على مواقع إلكترونية متعددة. على المستخدم تسجيل الدخول مرة أخرى لكل عملية تضمين على موقع إلكتروني مختلف.
حماية نقطة النهاية باستخدام "سياسة أمان المحتوى"
في حين تحدّد "سياسة الأذونات" ما إذا كان بإمكان إطار iframe تشغيل WebAuthn، تحدّد سياسة أمان المحتوى (CSP) الجهات المسموح لها باستضافة إطار iframe.
بالنسبة إلى نقطة نهاية المصادقة، من الضروري التأكّد من أنّ المواقع الإلكترونية الشريكة المصرَّح لها أو مواقعك الإلكترونية فقط يمكنها تحميل الإطار الفرعي لتسجيل الدخول، ما يمنع محاولات النقر غير المصرَّح بها قبل أن يتم تحميل واجهة المستخدم.
استخدام frame-ancestors
يحدّد frame-ancestors
التوجيه
الصفحات الرئيسية الصالحة التي يمكنها تضمين موقعك الإلكتروني. من خلال إضافة نطاقات إلى هذا التوجيه، يمكنك السماح للنطاقات المسموح لها بتضمين الإطار الفرعي لتسجيل الدخول.
Content-Security-Policy: frame-ancestors 'self' https://parent-site.example.com;
سياسة أمان المحتوى: التوافق مع frame-ancestors:
المجموعة X-Frame-Options
يتيح العنوان القديم X-Frame-Options إمكانية مشابهة، ولكنّه لا يتيح سوى الخيارات الثنائية (DENY أو SAMEORIGIN). اضبط كلّاً من frame-ancestors وX-Frame-Options: DENY في حال كان المتصفّح لا يتوافق مع CSP. ويتم دائمًا إعطاء الأولوية لسياسة أمان المحتوى في الأماكن التي تتوفّر فيها.
X-Frame-Options: DENY
التوافق مع X-Frame-Options:
الثقة، ولكن مع التحقّق من جهة الخادم
تُقيّم عمليات التحقّق من جهة العميل في المتصفّح النية والأذونات، ولكن الخادم هو الحكم النهائي في ما يتعلّق بالثقة. تحقَّق من الردّ على خادم الجهة المعتمِدة (RP) للتأكّد من أنّ السياق صالح وموقَّع.
حمولة بيانات العميل
تتضمّن بيانات عميل WebAuthn مَعلمات مصمّمة خصيصًا لمساعدتك في التحقّق من سياق الطلب الذي تم إجراؤه في إطار iframe:
-
crossOrigin(قيمة منطقية): تشير إلى ما إذا تم استدعاء WebAuthn API داخل إطار iframe من مصادر متعددة. إذا كانت بنيتك تعتمد على إطارات iframe، يجب أن يفرض خادمك أن تكون قيمة هذا العلامةtrue. -
topOrigin(سلسلة): مصدر سياق التصفّح ذي المستوى الأعلى (ما يظهر في شريط العناوين في المتصفّح). يجب أن يتحقّق الخادم من ذلك من خلال مقارنته بقائمة تتضمّن المصادر المعروفة والمفوَّضة للوالدَين.
قائمة التحقّق من صحة البيانات
للتحقّق من صحة ردّ أداة المصادقة على خادمك، اتّبِع الخطوات التالية:
- تحليل وفك ترميز
collectedClientDataالمُوقَّع من ردّ أداة المصادقة. - تأكَّد من أنّ
typeيطابق الاحتفال (webauthn.getأوwebauthn.create). - التحقّق من تواجد المستخدم وتوقيعه
- إذا كان من المفترض أن يأتي الطلب من بنية إطار iframe:
- فرض
crossOrigin === true - فرض تطابق
topOriginمع قائمتك المعتمَدة لمصادر الوالدَين
- فرض
إنشاء جلسات بأمان باستخدام postMessage()
لإنشاء جلسة بشكل موثوق، يجب أن تمرّر إطار iframe رمز المصادقة مرة أخرى إلى الصفحة الرئيسية باستخدام postMessage()، ما يتيح للصفحة الرئيسية إدارة حالة الجلسة في سياق الطرف الأول الخاص بها.
سير العمل الآمن
لإنشاء جلسة آمنة، اتّبِع سير العمل التالي:
- تأكَّد من أنّ عنوان URL لإطار iframe يتضمّن مَعلمات طلب البحث
srcوnonceوorigin:- استخدِم قيمة عشوائية للسمة
nonce. يعملnonceكرمز مميّز للتحقّق من الأمان لضمان أنّ رمز المصادقة الذي تم تلقّيه من إطار iframe يتطابق بشكل صحيح مع الجلسة المحدّدة التي بدأتها الصفحة الرئيسية. - استخدِم نطاق الإطار الرئيسي لـ
origin. تحدّد المَعلمةoriginمصدر الصفحة الرئيسية، ما يتيح للإطار iframe تحديد السياق المصرّح به الذي تم تضمينه فيه بشكل آمن.
- استخدِم قيمة عشوائية للسمة
- يكمل إطار iframe عملية مصادقة WebAuthn باستخدام الخادم الخاص به.
يصدر خادم إطار iframe رمزًا مميزًا، مثل JWT، يتضمّن
nonceويتم توجيهه إلى الصفحة الرئيسية.// Extract nonce and origin from the URL params const urlParams = new URLSearchParams(window.location.search); const nonce = urlParams.get('nonce'); const origin = urlParams.get('origin'); if (!nonce || !origin) { alert('Nonce or origin is missing in the URL'); return; } // Create a JWT const response = await post('/createToken', { nonce, origin }); const token = response.token; // Post the JWT to the parent frame window.parent.postMessage({ token }, origin);تستمع الصفحة الرئيسية إلى الحدث
message، وتتحقّق من صحة مصدر المرسِل، وتتأكّد من الرمز المميّز.window.addEventListener("message", (event) => { if (event.origin !== "https://embedded-auth.example.com") return; // Verify the received JWT const result = await post('/verifyIdToken', { token: event.data.token, origin: provider.origin, }); });تحتفظ الصفحة الرئيسية بالجلسة إذا تم التحقّق من صحة رمز JWT بنجاح.
يتحمّل كل من المرسِل والمستلِم مسؤوليات الأمان التالية:
- المُرسِل (iframe): حدِّد دائمًا مصدرًا مستهدفًا دقيقًا عند إرسال الرسائل (لا تستخدِم
"*"مطلقًا). - المستلِم (الوالد): يجب دائمًا التحقّق من
event.originعند تلقّي الرسائل لمنع انتحال المصدر.
الخاتمة
يعتمد الاستخدام الآمن لإطارات iframe على "سياسة الأذونات" للتفعيل، و"سياسة أمان المحتوى" للتقييد، وملفات تعريف الارتباط المجزّأة التابعة لجهات خارجية لاستمرار الجلسة، والتحقّق من جهة الخادم من سياق العميل، ونقل الجلسة الواعي بالسياق باستخدام postMessage().
لمزيد من المعلومات حول المواضيع ذات الصلة، يمكنك متابعة مدوّنة مطوّري Chrome من Google واستكشاف المزيد من المراجع في مستندات هوية مطوّر Chrome.