الخلاصة

  • أتاح رأس الاستجابة X-Frame-Options: SAMEORIGIN للصفحة أن تطلب رفض تضمينها داخل إطار تابع لموقع آخر. وثّقت مذكرة RFC عام 2013 ثغرة في طريقة الفحص: بعض المتصفحات قارنت الصفحة المحمية بالصفحة العليا فقط.
  • صفحة من A تحتوي B، وB تحتوي صفحة محمية من A. يرى الفحص المحدود طرفين من A ويغفل B في الوسط. فرضت قاعدة frame-ancestors الصادرة عن W3C في 2016 فحص كل سلف قبل عرض الصفحة.

الإطار الذي اختبأ بين صفحتين

تفتح صفحة من الموقع A إطاراً لموقع B. يحاول B أن يعرض داخل إطاره صفحة حساسة من A. ترسل الصفحة الحساسة X-Frame-Options: SAMEORIGIN كي يسمح المتصفح بالتضمين من المصدر نفسه فقط. إذا نظر المتصفح إلى الصفحة العليا وقارنها بالصفحة الحساسة، فسيرى A في الجانبين ويقبل. تبقى صفحة B التي تحيط مباشرة بالمحتوى المحمي خارج الفحص.

شرح RFC 7034 المنشور في أكتوبر 2013 هذا الترتيب. الوثيقة معلوماتية وتسجل استخدام الرأس واختلاف التنفيذ آنذاك. الغرض من الرأس مقاومة اختطاف النقرات، حيث تُركّب واجهة فوق أخرى فيضغط المستخدم زرّاً في صفحة لا يقصدها. مثال تأكيد الشراء في الوثيقة يشرح وسيلة دفاع. أما سلسلة A/B/A فهي آلية موثقة، ولا تسجل حادثة متجر معين.

الخادم أصدر الأمر، والمتصفح اختار موضع النظر

كان خادم الصفحة المحمية يضع السياسة في استجابة HTTP. تعني DENY رفض أي إطار، وتسمح SAMEORIGIN بالإطار من المصدر نفسه، بينما تحدد ALLOW-FROM مصدراً واحداً مسموحاً. ينفذ المتصفح ما يطلبه صاحب الصفحة. ينجح هذا التقسيم عندما يوجد مستويان فقط. وعندما تتداخل ثلاثة مستويات، تصبح طريقة معرفة «المصدر نفسه» مسألة مرتبطة بالطبقة التي يفحصها البرنامج.

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

فحص كل سلف

حددت توصية W3C الخاصة بـ Content Security Policy Level 2 في ديسمبر 2016 قاعدة frame-ancestors. قبل تحميل المورد داخل إطار، يجمع المتصفح قائمة جميع النوافذ الأسلاف، ويقارن عنوان كل صفحة بالمصادر المسموح بها. يكفي فشل سلف واحد لإيقاف التحميل. في المثال A/B/A تفشل صفحة B، وإن كانت النافذة العليا من A.

قارن نص W3C هذه الطريقة صراحة بفحص الصفحة العليا فقط في كثير من تطبيقات SAMEORIGIN. وقال إن frame-ancestors تحل محل X-Frame-Options، وينبغي تقديم سياسة CSP حين تصل السياستان معاً. أتاحت القاعدة الجديدة أيضاً أكثر من مصدر مسموح، بخلاف ALLOW-FROM. الإصلاح الأساسي هو فحص كل حلقة في السلسلة.

وضع السياسة في الاستجابة جزء من عملها. ذكرت وثيقة RFC أن المتصفح يتجاهل X-Frame-Options إذا وُضع في عنصر meta http-equiv بدلاً من رأس HTTP. ولا تقبل مواصفة W3C نقل frame-ancestors عبر عنصر meta. كما أن default-src 'none' وحدها لا تمنع تضمين الصفحة. على الموقع أن يرسل قاعدة التضمين في المكان الذي يطبقها المتصفح.

صاحب الصفحة يحدد من يمكنه إحاطتها. ومتصفح الزائر وحده يرى ترتيب الإطارات الحقيقي. قيمة الحد المكتوب تتوقف على عدد الطبقات التي يصل إليها الفحص المنفذ.