حماية الموارد من هجمات الويب باستخدام ميزة "جلب البيانات الوصفية"

منع تسرُّب معلومات CSRF وXSSI والمعلومات المتعددة المصادر.

لماذا يجب الانتباه إلى عزل موارد الويب؟

تتعرّض العديد من تطبيقات الويب لهجمات من مصادر مختلفة، مثل تزوير الطلبات من مواقع إلكترونية مختلفة (CSRF) وإدراج البرامج النصية على مواقع إلكترونية مختلفة (XSSI) وهجمات التوقيت وتسرُّب المعلومات من مصادر مختلفة أو هجمات قناة التنفيذ التوقّعي (Spectre).

تسمح لك رؤوس طلب Fetch Metadata بنشر آلية دفاعية قوية ومفصّلة، وهي سياسة عزل الموارد، لحماية تطبيقك من هذه الهجمات الشائعة المشتركة المصدر.

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

توافُق المتصفح

إنّ عناوين طلبات استرجاع البيانات الوصفية متوافقة مع جميع محرّكات المتصفّحات الحديثة.

دعم المتصفح

  • Chrome: 76
  • الحافة: 79.
  • Firefox: 90
  • ‫Safari: 16.4

المصدر

الخلفية

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

تشبه الهجمات الأخرى على مستوى الموقع الإلكتروني، مثل تضمين النصوص البرمجية على مستوى الموقع الإلكتروني (XSSI) أو تسرُّب المعلومات من مصادر متعددة، هجوم CSRF من حيث الطبيعة، وتعتمد على تحميل الموارد من تطبيق ضحية في مستند يتحكّم فيه المهاجم وتسرُّب معلومات عن التطبيقات الضحية. وبما أنّ التطبيقات لا يمكنها بسهولة التمييز بين الطلبات الموثوق بها والطلبات غير الموثوق بها، لا يمكنها تجاهل الزيارات الضارة على مستوى المواقع الإلكترونية.

تقديم ميزة "جلب البيانات الوصفية"

عناوين طلب Fetch Metadata هي ميزة جديدة لأمان منصات الويب مصمّمة لمساعدة الخوادم في الدفاع عن نفسها ضد الهجمات من مصادر متعددة. من خلال توفير معلومات عن سياق طلب HTTP في مجموعة من عناوين Sec-Fetch-*، يتم السماح لخادم الاستجابة بتطبيق سياسات الأمان قبل معالجة الطلب. ويتيح ذلك للمطوّرين تحديد ما إذا كان سيتم قبول الطلب أو رفضه استنادًا إلى طريقة تقديمه والسياق الذي سيتم استخدامه فيه، ما يتيح إمكانية الردّ على الطلبات المشروعة فقط التي يتم تقديمها من خلال تطبيقاتهم الخاصة.

Same-Origin
سيستمر عمل الطلبات الواردة من المواقع الإلكترونية التي يعرضها خادمك (المصدر نفسه). يؤدي طلب الجلب من https://site.example للمورد https://site.example/foo.json في JavaScript إلى أن يُرسِل المتصفّح رأس طلب HTTP "Sec Fetch-Site: same-origin".
على مستوى المواقع الإلكترونية
قد يرفض الخادم الطلبات الضارة من مواقع إلكترونية متعددة بسبب السياق الإضافي في طلب HTTP الذي تقدّمه عناوين Sec-Fetch-*. هناك صورة في https://evil.example تم ضبط السمة src لعنصر img على "https://site.example/foo.json" وتتسبب في إرسال المتصفِّح لعنوان طلب HTTP وهو "Sec-Fetch-Site: cross-site".

Sec-Fetch-Site

دعم المتصفح

  • Chrome: 76
  • ‫Edge: 79
  • Firefox: 90
  • Safari: الإصدار 16.4.

المصدر

يخبر Sec-Fetch-Site الخادم باسم الموقع الإلكتروني الذي أرسل الطلب. ويضبط المتصفّح هذه القيمة على إحدى القيم التالية:

  • same-origin، إذا تم تقديم الطلب من خلال تطبيقك (مثل site.example)
  • same-site، إذا تم تقديم الطلب من خلال نطاق فرعي لموقعك الإلكتروني (مثل bar.site.example)
  • none، إذا كان الطلب قد نتج بشكل صريح عن تفاعل أحد المستخدمين مع وكيل المستخدم (مثل النقر على إشارة مرجعية)
  • cross-site، إذا تم إرسال الطلب من خلال موقع إلكتروني آخر (مثل evil.example)

Sec-Fetch-Mode

توافق المتصفّح

  • Chrome: 76.
  • ‫Edge: 79
  • Firefox: 90
  • Safari: الإصدار 16.4.

المصدر

تشير السمة Sec-Fetch-Mode إلى وضع الطلب. ويتوافق هذا تقريبًا مع نوع الطلب، ويتيح لك التفريق بين عمليات تحميل الموارد وطلبات التنقل. على سبيل المثال، تشير وجهة navigate إلى طلب التنقّل على المستوى الأعلى، بينما تشير no-cors إلى طلبات الموارد، مثل تحميل صورة.

Sec-Fetch-Dest

دعم المتصفح

  • Chrome: 80
  • الحافة: 80
  • Firefox: 90
  • Safari: الإصدار 16.4.

المصدر

تعرض السمة Sec-Fetch-Dest وجهة الطلب (على سبيل المثال، إذا تسبّبت علامة script أو img في طلب المتصفّح لمورد).

كيفية استخدام Fetch Metadata للحماية من الهجمات من مصادر متعددة

المعلومات الإضافية التي تقدمها عناوين الطلبات هذه بسيطة للغاية، ولكن السياق الإضافي يتيح لك إنشاء منطق أمان قوي من جانب الخادم، ويشار إليه أيضًا باسم "سياسة عزل الموارد"، باستخدام بضعة أسطر من الرموز.

تنفيذ سياسة عزل الموارد

تمنع سياسة عزل الموارد المواقع الإلكترونية الخارجية من طلب مواردك. ويؤدي حظر هذه الزيارات إلى تخفيف الثغرات الأمنية الشائعة على الويب على مستوى المواقع الإلكترونية المختلفة، مثل هجمات CSRF وXSSI وهجمات التوقيت وتسرُّب المعلومات من مصادر مختلفة. يمكن تفعيل هذه السياسة لجميع نقاط النهاية في تطبيقك، وستسمح بجميع طلبات الموارد الواردة من تطبيقك بالإضافة إلى عمليات التنقّل المباشرة (عبر طلب HTTP GET). يمكن إيقاف نقاط النهاية التي من المفترض أن يتم تحميلها في سياق مواقع إلكترونية متعددة (مثل نقاط النهاية التي يتم تحميلها باستخدام سياسة مشاركة الموارد المتعددة المصادر (CORS)) من هذا المنطق.

الخطوة 1: السماح بالطلبات الواردة من المتصفّحات التي لا ترسل البيانات الوصفية لعمليات الجلب

بما أنّ بعض المتصفّحات لا تتيح استخدام ميزة "جلب البيانات الوصفية"، عليك السماح بالطلبات التي لا تضبط رؤوس Sec-Fetch-* من خلال التحقّق من توفّر sec-fetch-site.

if not req['sec-fetch-site']:
  return True  # Allow this request

الخطوة 2: السماح بالطلبات التي بدأها المتصفّح نفسه وعلى الموقع الإلكتروني نفسه

وسيتم السماح بأي طلبات لا تنشأ من سياق من مصادر متعددة (مثل evil.example). وعلى وجه الخصوص، في ما يلي الطلبات التي:

  • أن تكون واردة من تطبيقك (مثل طلب من المصدر نفسه حيث سيتم دائمًا السماح دائمًا بطلبات site.example/foo.json من site.example).
  • أن تأتي من نطاقاتك الفرعية
  • أن تكون ناتجة صراحةً عن تفاعل المستخدم مع وكيل المستخدم (مثلاً، التنقل المباشر أو النقر على إشارة مرجعية وما إلى ذلك)
if req['sec-fetch-site'] in ('same-origin', 'same-site', 'none'):
  return True  # Allow this request

الخطوة 3: السماح بالتنقّل البسيط على المستوى الأعلى وإضافة إطارات iframe

لضمان استمرار إمكانية ربط موقعك الإلكتروني من مواقع إلكترونية أخرى، عليك السماح بالتنقّل البسيط (HTTP GET) على المستوى الأعلى.

if req['sec-fetch-mode'] == 'navigate' and req.method == 'GET'
  # <object> and <embed> send navigation requests, which we disallow.
  and req['sec-fetch-dest'] not in ('object', 'embed'):
    return True  # Allow this request

الخطوة 4: إيقاف نقاط النهاية التي تهدف إلى تقديم زيارات من مواقع إلكترونية متعددة (اختياري)

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

  • نقاط النهاية المطلوب الوصول إليها من مصادر متعددة: إذا كان تطبيقك يعرض نقاط نهاية تم تفعيل CORS فيها، عليك إيقاف ميزة عزل الموارد في تطبيقك صراحةً لضمان استمرار إمكانية إرسال طلبات من مواقع إلكترونية متعددة إلى نقاط النهاية هذه.
  • الموارد المتاحة للجميع (مثل الصور والأنماط وما إلى ذلك): يمكن أيضًا استثناء أيّ مصادر عامة وغير مُعتمَدة يجب أن تكون قابلة للتحميل من مصادر متعددة من مواقع إلكترونية أخرى.
if req.path in ('/my_CORS_endpoint', '/favicon.png'):
  return True

الخطوة 5: رفض جميع الطلبات الأخرى التي تتجاوز نطاق الموقع الإلكتروني وليست لأغراض التنقّل

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

مثال: يوضّح الرمز البرمجي التالي تنفيذًا كاملاً لسياسة عزل الموارد القوية على الخادم أو كوسيط لرفض طلبات الموارد التي يُحتمل أن تكون ضارة على مستوى المواقع الإلكترونية، مع السماح بطلبات التنقّل البسيطة:

# Reject cross-origin requests to protect from CSRF, XSSI, and other bugs
def allow_request(req):
  # Allow requests from browsers which don't send Fetch Metadata
  if not req['sec-fetch-site']:
    return True

  # Allow same-site and browser-initiated requests
  if req['sec-fetch-site'] in ('same-origin', 'same-site', 'none'):
    return True

  # Allow simple top-level navigations except <object> and <embed>
  if req['sec-fetch-mode'] == 'navigate' and req.method == 'GET'
    and req['sec-fetch-dest'] not in ('object', 'embed'):
      return True

  # [OPTIONAL] Exempt paths/endpoints meant to be served cross-origin.
  if req.path in ('/my_CORS_endpoint', '/favicon.png'):
    return True

  # Reject all other requests that are cross-site and not navigational
  return False

نشر سياسة عزل الموارد

  1. ثبِّت وحدة مثل مقتطف الرمز أعلاه لتسجيل سلوك موقعك الإلكتروني ومراقبته، والتأكّد من أنّ القيود لا تؤثر في أي زيارات مشروعة.
  2. أصلِح الانتهاكات المحتملة من خلال استثناء نقاط النهاية المشروعة المتعددة المصادر.
  3. نفِّذ السياسة عن طريق حذف الطلبات غير الممتثلة للسياسة.

تحديد انتهاكات السياسة وإصلاحها

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

بناءً على خبرتنا في طرح سياسة عزل موارد البيانات الوصفية في Google، تكون معظم التطبيقات متوافقة تلقائيًا مع هذه السياسة ونادرًا ما تتطلب نقاط نهاية معفاة للسماح بالزيارات من مواقع إلكترونية متعددة.

فرض سياسة عزل الموارد

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

مراجع إضافية