سياسة أمان المحتوى

جو ميدلي
جو ميدلي

نموذج أمان الويب يستند إلى سياسة المصدر نفسه. يجب ألا يتمكّن الرمز البرمجي من https://mybank.com إلا من الوصول إلى بيانات https://mybank.com، وبالتأكيد يجب عدم السماح لـ https://evil.example.com بالوصول إلى تلك البيانات مطلقًا. يتم عزل كل مصدر من المواقع الإلكترونية الأخرى، ما يوفّر للمطوّرين بيئة حماية آمنة يمكن من خلالها إنشاء المحتوى ولعبه. من الناحية النظرية، هذا رائع للغاية. من الناحية العملية، وجد المهاجمون طرقًا ذكية لتدمير النظام.

على سبيل المثال، يمكنك تجاوز سياسة المصدر نفسها من خلال خداع موقع إلكتروني لتحويل رمز ضار إلى جانب المحتوى المقصود من خلال هجمات النصوص البرمجية على المواقع الإلكترونية (XSS). وهذه مشكلة كبيرة، حيث تثق المتصفحات في أنّ جميع الرموز البرمجية التي تظهر في الصفحة تشكّل جزءًا شرعيًا من مصدر أمان تلك الصفحة. ورقة المعلومات المرجعية لـ XSS هي عبارة عن مقطع عرضي قديم ولكنه تمثيلي من الطرق التي قد يستخدمها المهاجم لانتهاك هذه الثقة عن طريق إدخال رمز ضار. إذا أدخل المهاجم أي رمز برمجي بنجاح، قد تنتهي اللعبة كثيرًا: يتم اختراق بيانات جلسات المستخدم واستخراج المعلومات التي يجب الحفاظ على سرّيتها إلى The Bad Guys. من الواضح أننا نرغب في منع حدوث ذلك إن أمكن.

تسلّط هذه النظرة العامة الضوء على وسيلة دفاعية يمكن أن تقلّل بشكل كبير من خطر هجمات XSS وتأثيرها في المتصفّحات الحديثة: سياسة أمان المحتوى (CSP).

الملخّص

  • استخدِم القوائم المسموح بها لإعلام العميل بالعناصر المسموح بها وغير المسموح بها.
  • تعرَّف على التوجيهات المتاحة.
  • تعرّف على الكلمات الرئيسية التي يستخدمونها.
  • يُعتبَر الرمز المضمّن وeval() ضارًا.
  • أبلِغ خادمك عن انتهاكات السياسة قبل تنفيذها.

القوائم المسموح بها للمصادر

تكمن المشكلة التي تستغلها هجمات XSS في عدم قدرة المتصفّح على التمييز بين النص البرمجي الذي يشكّل جزءًا من التطبيق والنص البرمجي الذي تم إدخاله عن طريق جهة خارجية عن طريق الخطأ. على سبيل المثال، يعمل زر Google +1 في أسفل هذه الصفحة على تحميل وتنفيذ الرمز من https://apis.google.com/js/plusone.js في سياق أصل هذه الصفحة. نحن نثق في هذا الرمز، ولكن لا نتوقّع من المتصفّح أن يكتشف من تلقاء نفسه أنّ الرمز البرمجي من apis.google.com رائع، في حين أنّ الترميز من apis.evil.example.com غير صحيح على الأرجح. ويعمل المتصفح بسهولة على تنزيل أي رمز تطلبه الصفحة وتنفيذه بغض النظر عن المصدر.

فبدلاً من الوثوق بشكلٍ كامل في كل ما يقدمه الخادم، يحدّد CSP عنوان HTTP Content-Security-Policy الذي يسمح لك بإنشاء قائمة مسموح بها من مصادر المحتوى الموثوق به ويطلب من المتصفح تنفيذ أو عرض الموارد من هذه المصادر فقط. وحتى في حال تمكّن المهاجم من العثور على فجوة لإدخال نص برمجي، لن يتطابق النص البرمجي مع القائمة المسموح بها، وبالتالي لن يتم تنفيذه.

وبما أنّنا نثق في تقديم apis.google.com رمز صالح ونثق بأنفسنا لفعل الشيء نفسه، لنحدد سياسة تسمح بتنفيذ النص البرمجي فقط عندما يكون مصدره أحد هذين المصدرين:

Content-Security-Policy: script-src 'self' https://apis.google.com

أمر بسيط للغاية، أليس كذلك؟ وكما خمنت على الأرجح، فإنّ script-src هو توجيه يتحكّم في مجموعة من الامتيازات المتعلّقة بالنصوص البرمجية لصفحة محدّدة. لقد حدّدنا 'self' كمصدر صالح للنص البرمجي وhttps://apis.google.com كمصدر آخر. ينزِّل المتصفّح وينفّذ JavaScript بدقة من apis.google.com عبر HTTPS، وكذلك من مصدر الصفحة الحالية.

خطأ في وحدة التحكم: تم رفض تحميل النص البرمجي "http://evil.example.com/evil.js" لأنه ينتهك توجيهات سياسة أمان المحتوى التالية: script-src 'self' https://apis.google.com

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

تنطبق السياسة على مجموعة كبيرة من الموارد

على الرغم من أنّ موارد النصوص البرمجية هي الأكثر وضوحًا ضمن المخاطر الأمنية، توفّر سياسة أمان المحتوى (CSP) مجموعة كبيرة من توجيهات السياسات التي تتيح التحكّم بشكل دقيق إلى حدّ ما في الموارد التي يُسمح بتحميل الصفحة بتحميلها. لقد رأيت script-src، لذا يجب أن يكون المفهوم واضحًا.

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

  • تفرض base-uri قيودًا على عناوين URL التي يمكن أن تظهر في عنصر <base> للصفحة.
  • تعرض child-src عناوين URL للعاملين ومحتوى الإطارات المضمّن. على سبيل المثال: تتيح السمة child-src https://youtube.com تضمين فيديوهات من YouTube وليس من مصادر أخرى.
  • تفرض connect-src قيودًا على المصادر التي يمكنك الاتصال بها (عبر XHR وWebSockets وEventSource).
  • تحدّد font-src المصادر التي يمكن أن تعرض خطوط الويب. يمكن تفعيل خطوط الويب من Google من خلال font-src https://themes.googleusercontent.com.
  • يسرد form-action نقاط نهاية صالحة للإرسال من علامات <form>.
  • تحدد frame-ancestors المصادر التي يمكنها تضمين الصفحة الحالية. ينطبق هذا التوجيه على العلامات <frame> و<iframe> و<embed> و<applet>. لا يمكن استخدام هذا التوجيه في علامات <meta> ولا ينطبق إلا على الموارد التي ليست بتنسيق HTML.
  • تم ايقاف frame-src في المستوى 2 ولكن استعادته في المستوى 3. في حال عدم توفّره، ستبقى الصفحة "child-src" كما في السابق.
  • تحدِّد img-src المصادر التي يمكن تحميل الصور منها.
  • تفرض media-src قيودًا على المصادر المسموح لها بعرض الفيديو والصوت.
  • تسمح object-src بالتحكم في Flash والمكوّنات الإضافية الأخرى.
  • تفرض plugin-types قيودًا على أنواع المكوّنات الإضافية التي قد تستدعيها الصفحة.
  • تحدّد report-uri عنوان URL الذي سيرسل إليه المتصفّح تقارير عند انتهاك إحدى سياسات أمان المحتوى. ولا يمكن استخدام هذا التوجيه في علامات <meta>.
  • style-src هي نظير script-src لأوراق الأنماط.
  • توجِّه upgrade-insecure-requests برامج وكيل المستخدم إلى إعادة كتابة مخططات عناوين URL، مع تغيير HTTP إلى HTTPS. هذا التوجيه معني بمواقع الويب التي تتضمن أعدادًا كبيرة من عناوين URL القديمة والتي تحتاج إلى إعادة كتابتها.
  • worker-src هو توجيه من المستوى 3 من سياسة أمان المحتوى (CSP) يحدّ من عناوين URL التي قد يتم تحميلها كعامل تشغيل أو عامل مشترَك أو مشغّل خدمات. اعتبارًا من تموز (يوليو) 2017، أصبح هذا التوجيه لديه عمليات تنفيذ محدودة.

وتكون التوجيهات مفتوحة على نطاق واسع تلقائيًا. إذا لم تضبط سياسة محدّدة لتوجيه، لنقل font-src، يعمل هذا التوجيه بشكل تلقائي على الرغم من أنّك حددت * كمصدر صالح (على سبيل المثال، يمكنك تحميل الخطوط من أي مكان بدون قيود).

يمكنك إلغاء هذا السلوك التلقائي من خلال تحديد أمر default-src. يحدد هذا التوجيه الإعدادات الافتراضية لمعظم التوجيهات التي تتركها بدون تحديد. بشكل عام، ينطبق ذلك على أي توجيه ينتهي بـ -src. في حال ضبط default-src على https://example.com وعدم تحديد توجيه font-src، يمكنك تحميل الخطوط من https://example.com وليس من أي مكان آخر. لقد حدّدنا السمة script-src فقط في الأمثلة السابقة، ما يعني أنّه يمكن تحميل الصور والخطوط وغيرها من أي مصدر.

ولا تستخدم التوجيهات التالية default-src كإجراء احتياطي. تذكر أن الفشل في تعيينها يمثل السماح بأي شيء.

  • base-uri
  • form-action
  • frame-ancestors
  • plugin-types
  • report-uri
  • sandbox

يمكنك استخدام العديد من هذه التوجيهات أو القليل منها على النحو الملائم لتطبيقك المحدد، ما عليك سوى إدراج كل منها في عنوان HTTP، مع فصل التوجيهات بفواصل منقوطة. احرِص على إدراج جميع الموارد المطلوبة من نوع معيّن في توجيه واحد. إذا كتبت شيئًا مثل script-src https://host1.com; script-src https://host2.com، سيتم ببساطة تجاهل التوجيه الثاني. شيء مثل ما يلي من شأنه أن يحدد بشكل صحيح كلا المصدرين على أنهما صالحان:

script-src https://host1.com https://host2.com

على سبيل المثال، إذا كان لديك تطبيق يُحمِّل جميع موارده من شبكة توصيل المحتوى (على سبيل المثال، https://cdn.example.net)، وكنت تعرف أنّك لا تحتاج إلى أي محتوى ذي إطار أو مكوّنات إضافية، قد تبدو سياستك على النحو التالي:

Content-Security-Policy: default-src https://cdn.example.net; child-src 'none'; object-src 'none'

تفاصيل التنفيذ

سترى عنوانَي X-WebKit-CSP وX-Content-Security-Policy في برامج تعليمية مختلفة على الويب. من الآن فصاعدًا، يجب عليك تجاهل هذه الرؤوس التي تبدأ ببادئة. تتيح المتصفحات الحديثة (باستثناء IE) استخدام عنوان Content-Security-Policy غير المسبوق. هذا هو العنوان الذي يجب عليك استخدامه.

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

تتسم قائمة المصدر في كل توجيه بالمرونة. يمكنك تحديد المصادر حسب النظام (data: أو https:) أو حسب النطاق المحدّد من اسم المضيف فقط (example.com، الذي يتطابق مع أي مصدر على هذا المضيف: أي نظام أو أي منفذ) ومعرّف موارد منتظم (URI) مؤهّل بالكامل (https://example.com:443، والذي يطابق فقط HTTPS وexample.com والمنفذ 443 فقط). يمكن استخدام أحرف البدل، ولكن يمكن استخدامها فقط كمخطط أو منفذ أو في أقصى يسار اسم المضيف: سيطابق *://*.example.com:* جميع النطاقات الفرعية example.com (ولكن وليس example.com نفسها)، باستخدام أي مخطط، على أي منفذ.

تقبل قائمة المصادر أيضًا أربع كلمات رئيسية:

  • لا تطابق 'none'، كما قد تتوقع، أي شيء.
  • تتطابق السمة 'self' مع المصدر الحالي، ولكن لا تتطابق مع نطاقاته الفرعية.
  • تسمح 'unsafe-inline' بتضمين لغة JavaScript وCSS. (سنتناول هذا بمزيد من التفصيل بعد قليل).
  • تسمح 'unsafe-eval' بآليات تحويل النص إلى JavaScript، مثل eval. (سنصل إلى ذلك أيضًا).

تتطلب هذه الكلمات الرئيسية علامات اقتباس مفردة. على سبيل المثال، يسمح الحقل script-src 'self' (مع علامتي اقتباس) بتنفيذ JavaScript من المضيف الحالي، بينما يسمح script-src self (بدون علامات اقتباس) باستخدام JavaScript من خادم اسمه "self" (وليس من المضيف الحالي)، وهذا على الأرجح ليس ما تقصده.

وضع الحماية

هناك توجيه آخر يستحق الحديث عنه: sandbox. يختلف الأمر قليلاً عن الإجراءات الأخرى التي نظرنا إليها، حيث يتم فرض قيود على الإجراءات التي يمكن للصفحة اتخاذها بدلاً من الموارد التي يمكن للصفحة تحميلها. في حال توفّر التوجيه sandbox، يتم التعامل مع الصفحة كما لو تم تحميلها داخل <iframe> باستخدام السمة sandbox. وقد ينتج عن ذلك مجموعة كبيرة من التأثيرات على الصفحة، مثل فرض مصدر فريد على الصفحة ومنع إرسال النموذج وغير ذلك. يتجاوز الأمر نطاق هذه المقالة بعض الشيء، ولكن يمكنك العثور على التفاصيل الكاملة حول السمات الصالحة لوضع الحماية في قسم "وضع الحماية" ضمن مواصفات HTML5.

العلامة الوصفية

آلية التسليم المفضّلة لمقدّمي خدمة CSS هي عنوان HTTP. مع ذلك، قد يكون من المفيد ضبط سياسة على صفحة في الترميز مباشرةً. يمكنك إجراء ذلك باستخدام علامة <meta> مع السمة http-equiv:

<meta
  http-equiv="Content-Security-Policy"
  content="default-src https://cdn.example.net; child-src 'none'; object-src 'none'"
/>

لا يمكن استخدام هذا الاسم مع frame-ancestors أو report-uri أو sandbox.

يُعتبر الرمز المضمّن ضارًا.

يجب أن يكون واضحًا أنّ سياسة أمان المحتوى (CSP) تستند إلى مصادر القائمة المسموح بها، لأنّ هذه طريقة لا لبس فيها لإرشاد المتصفِّح إلى التعامل مع مجموعات محدّدة من الموارد على أنّها مقبولة ورفض الباقي. مع ذلك، لا تنجح القوائم المسموح بها المستندة إلى المصدر في معالجة أكبر تهديد تشكِّله هجمات XSS، وهو إدخال النصوص البرمجية المضمّنة. إذا تمكّن مهاجم من إدخال علامة نص برمجي تحتوي مباشرةً على جزء من حمولة البيانات الضارة (<script>sendMyDataToEvilDotCom();</script>)، لن تتوفّر للمتصفِّح آلية لتمييزها عن علامة نص برمجي مضمّنة صالحة. تحل سياسة CSP هذه المشكلة من خلال حظر النصوص البرمجية المضمّنة تمامًا، فهي الطريقة الوحيدة للتأكد.

لا يشمل هذا الحظر النصوص البرمجية المضمَّنة مباشرةً في علامات script فحسب، بل يشمل أيضًا معالِجات الأحداث المضمَّنة وعناوين URL لبرامج javascript:. عليك نقل محتوى علامات script إلى ملف خارجي واستبدال عناوين URL لبرامج javascript: وعنوان <a ... onclick="[JAVASCRIPT]"> باستدعاءات addEventListener() مناسبة. على سبيل المثال، يمكنك إعادة كتابة ما يلي من:

<script>
  function doAmazingThings() {
    alert('YOU AM AMAZING!');
  }
</script>
<button onclick="doAmazingThings();">Am I amazing?</button>

إلى شيء آخر مثل:

<!-- amazing.html -->
<script src="amazing.js"></script>
<button id="amazing">Am I amazing?</button>

<div style="clear:both;"></div>
// amazing.js
function doAmazingThings() {
  alert('YOU AM AMAZING!');
}
document.addEventListener('DOMContentLoaded', function () {
  document.getElementById('amazing').addEventListener('click', doAmazingThings);
});

تتمتع التعليمات البرمجية المُعاد كتابتها بعدد من المزايا التي تتعدى نجاحها في استخدام CSP؛ وهي من أفضل الممارسات، بغض النظر عن استخدامك لسياسة CSP. يمزج JavaScript المضمنة بين الهيكل والسلوك بالطريقة التي لا ينبغي لك استخدامها. فالموارد الخارجية أسهل في التخزين المؤقت في المتصفحات، وهي سهلة الفهم للمطورين، بالإضافة إلى تجميعها وتصغيرها. ستكتب تعليمات برمجية أفضل إذا قمت بالعمل لنقل التعليمات البرمجية إلى الموارد الخارجية.

يتم التعامل مع النمط المضمّن بالطريقة نفسها: يجب دمج كل من السمة style وعلامتَي style في أوراق أنماط خارجية للحماية من مجموعة متنوعة من طرق استخراج البيانات الذكية بشكل مدهش التي توفّرها خدمة CSS.

إذا كان يجب تضمين نص برمجي ونمط مضمّنَين، يمكنك تفعيلهما عن طريق إضافة 'unsafe-inline' كمصدر مسموح به في توجيه script-src أو style-src. يمكنك أيضًا استخدام nonce أو التجزئة (انظر أدناه)، لكن لا يجب ذلك. إنّ حظر النص البرمجي المضمّن هو أكبر مكاسب أمنية يوفّرها CSP، ويؤدي حظر النمط المضمَّن إلى تعزيز أمان تطبيقك. يتطلب الأمر بعض الجهد مقدمًا للتأكد من أن الأمور تعمل بشكل صحيح بعد نقل كل التعليمات البرمجية خارج السطر، ولكن هذه مقايضة جديرة بالقيام بها.

إذا كنت مضطرًا لاستخدامها

يوفّر المستوى 2 من سياسة أمان المحتوى (CSP) توافقًا مع الأنظمة القديمة للنصوص البرمجية المضمّنة من خلال السماح لك بإضافة نصوص برمجية مضمَّنة محدّدة إلى القائمة المسموح بها باستخدام رمز غير مشفّر (رقم يُستخدم مرة واحدة) أو تجزئة. على الرغم من أن هذا قد يكون مرهقًا، إلا أنه مفيد في حاجته.

لاستخدام nonce، امنح علامة النص البرمجي سمة nonce. ويجب أن تتطابق قيمتها مع قيمة واحدة في قائمة المصادر الموثوقة. مثال:

<script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">
  // Some inline code I can't remove yet, but need to asap.
</script>

الآن، أضِف nonce إلى توجيه script-src الملحق بالكلمة الرئيسية nonce-.

Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'

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

تعمل علامات التجزئة بالطريقة نفسها. بدلاً من إضافة رمز إلى علامة النص البرمجي، أنشِئ تجزئة SHA للنص البرمجي نفسه وأضِفه إلى توجيه script-src. على سبيل المثال، لنفترض أن صفحتك احتوت على ما يلي:

<script>
  alert('Hello, world.');
</script>

قد تحتوي سياستك على ما يلي:

Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng='

هناك بعض الأشياء التي يجب ملاحظتها هنا. تحدد البادئة sha*- الخوارزمية التي تُنشئ التجزئة. في المثال أعلاه، يتم استخدام sha256-. تتوافق سياسة أمان المحتوى (CSP) أيضًا مع الترميزَين sha384- وsha512-. عند إنشاء التجزئة، يجب عدم تضمين علامات <script>. وكذلك الأمر بالنسبة إلى الكتابة بالأحرف الكبيرة والمسافة البيضاء، بما في ذلك المسافة البيضاء البادئة أو اللاحقة.

سيقودك بحث Google حول إنشاء تجزئات SHA إلى حلول بأي عدد من اللغات. باستخدام الإصدار 40 من Chrome أو إصدار أحدث، يمكنك فتح "أدوات مطوّري البرامج" ثم إعادة تحميل صفحتك. ستحتوي علامة التبويب "وحدة التحكّم" على رسائل خطأ مع تجزئة sha256 الصحيحة لكلّ من النصوص البرمجية المضمّنة.

Eval أيضًا

حتى عندما لا يتمكن المهاجم من إدخال نص برمجي بشكل مباشر، قد يتمكن من خداع تطبيقك لتحويل نص غير نشط إلى نص JavaScript قابل للتنفيذ وتنفيذه نيابةً عنه. eval() والدالة الجديدة Function() وsetTimeout([string], ...) وsetInterval([string], ...) هي جميعها متجهات قد ينتهي من خلالها النص الذي تم إدخاله بتنفيذ شيء ضار بشكل غير متوقع. استجابة CSP الافتراضية لهذا الخطر هي منع كل هذه المتجهات تمامًا.

وينتج عن ذلك بعض التأثيرات في طريقة إنشاء التطبيقات:

  • يجب تحليل JSON عبر ميزة JSON.parse المضمَّنة بدلاً من الاعتماد على eval. تتوفر عمليات JSON الأصلية في كل متصفح منذ IE8، وهي آمنة تمامًا.
  • أعِد كتابة أي استدعاءات setTimeout أو setInterval تجريها حاليًا باستخدام دوال مضمّنة بدلاً من سلاسل. مثال:
setTimeout("document.querySelector('a').style.display = 'none';", 10);

سيكون أفضل على النحو التالي:

setTimeout(function () {
  document.querySelector('a').style.display = 'none';
}, 10);
  • تجنُّب إنشاء النماذج في وقت التشغيل: تستخدم العديد من مكتبات النماذج new Function() بشكل حر لتسريع عملية إنشاء النماذج في وقت التشغيل. إنه تطبيق رائع للبرمجة الديناميكية، لكنه يتعرض لخطر تقييم النص الضار. تتوافق بعض إطارات العمل مع سياسة CSP بشكل غير تقليدي، وترجع إلى محلّل لغوي فعّال في حال عدم توفّر eval. ومن الأمثلة الجيدة على ذلك توجيه ng-csp في AngularJS.

ومع ذلك، فإن الخيار الأفضل قد يكون لغة النماذج التي تقدم التجميع المسبق (على سبيل المثال، توفر الأعمدة المقودة). يمكن أن يجعل التجميع المسبق للنماذج تجربة المستخدم أسرع من التنفيذ الأسرع في وقت التشغيل، كما أنه أكثر أمانًا أيضًا. إذا كانت قيمة eval وتوفر العناصر المرتبطة بنص إلى JavaScript الضرورية في تطبيقك، يمكنك تفعيلها عن طريق إضافة 'unsafe-eval' كمصدر مسموح به في توجيه script-src، ولكننا لا ننصح بذلك بشدة. ويؤدي حظر إمكانية تنفيذ السلاسل إلى صعوبة تنفيذ المهاجم لرموز غير مصرَّح بها على موقعك الإلكتروني.

إعداد التقارير

تُعدّ قدرة سياسة أمان المحتوى (CSP) على حظر الموارد غير الموثوق بها من جهة العميل مكسبًا كبيرًا للمستخدمين، ولكن سيكون من المفيد جدًا إرسال نوع من الإشعارات مرة أخرى إلى الخادم حتى تتمكن من تحديد وإزالة أي أخطاء تسمح بإجراء عمليات الحقن الضار في المقام الأول. لتحقيق هذه الغاية، يمكنك توجيه المتصفّح إلى الإبلاغ عن المخالفات بتنسيق POST بتنسيق JSON إلى موقع جغرافي محدّد في توجيه report-uri.

Content-Security-Policy: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;

ستبدو هذه التقارير على النحو التالي:

{
  "csp-report": {
    "document-uri": "http://example.org/page.html",
    "referrer": "http://evil.example.com/",
    "blocked-uri": "http://evil.example.com/evil.js",
    "violated-directive": "script-src 'self' https://apis.google.com",
    "original-policy": "script-src 'self' https://apis.google.com; report-uri http://example.org/my_amazing_csp_report_parser"
  }
}

يحتوي هذا التقرير على مجموعة كبيرة من المعلومات التي ستساعدك في تتبُّع السبب المحدّد للانتهاك، بما في ذلك الصفحة التي وقعت فيها الانتهاك (document-uri)، ومُحيل تلك الصفحة (ملاحظة: على عكس حقل رأس HTTP، لا يحتوي المفتاح على خطأ إملائي) والمورد الذي انتهك سياسة الصفحة (blocked-uri) والتوجيه المحدّد الذي انتهك السياسة (violated-directive) والسياسة الكاملة للصفحة (original-policy).

إعداد التقارير فقط

إذا كنت قد بدأت حديثًا باستخدام سياسة أمان المحتوى (CSP)، ننصحك بتقييم الحالة الحالية لتطبيقك قبل طرح سياسة صارمة للمستخدمين. كخطوة أولى لعملية نشر كاملة، يمكنك أن تطلب من المتصفّح مراقبة إحدى السياسات والإبلاغ عن الانتهاكات بدون فرض القيود. بدلاً من إرسال عنوان Content-Security-Policy، أرسِل العنوان Content-Security-Policy-Report-Only.

Content-Security-Policy-Report-Only: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;

لن تحظر السياسة المحدّدة في وضع "إعداد التقارير فقط" الموارد المحظورة، ولكنها سترسل تقارير الانتهاكات إلى الموقع الجغرافي الذي تحدِّده. يمكنك أيضًا إرسال كلا العنوانين لفرض سياسة واحدة ومراقبة سياسة أخرى. هذه طريقة رائعة لتقييم تأثير التغييرات في سياسة أمان المحتوى (CSP) لتطبيقك: يمكنك تفعيل ميزة إعداد التقارير لسياسة جديدة ومراقبة عمليات الإبلاغ عن المخالفات وإصلاح أي أخطاء تظهر لك. وعندما تكون راضيًا عن تأثيرها، ابدأ في تطبيق السياسة الجديدة.

الاستخدام الفعلي

يمكن استخدام CSP 1 إلى حد كبير في Chrome وSafari وFirefox، لكنه متاح محدود للغاية في IE 10. ويمكنك الاطّلاع على خصوصيات على caniuse.com. يتوفّر المستوى 2 من سياسة أمان المحتوى في Chrome منذ الإصدار 40. نشرت المواقع الإلكترونية الضخمة مثل Twitter وFacebook العنوان (دراسة حالة Twitter جديرة بالقراءة)، والمعيار جاهز جدًا لبدء النشر على مواقعك الإلكترونية.

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

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

  • يتضمّن زر 1+ من Google نصًا برمجيًا من https://apis.google.com ويتضمّن <iframe> من https://plusone.google.com. تحتاج إلى سياسة تتضمن هذين المصدرين من أجل تضمين الزر. سيكون الحد الأدنى للسياسة هو script-src https://apis.google.com; child-src https://plusone.google.com. وتحتاج أيضًا إلى التأكّد من سحب مقتطف JavaScript الذي يوفّره محرّك بحث Google إلى ملف JavaScript خارجي. إذا كانت لديك سياسة مستنِدة إلى المستوى 1 باستخدام frame-src يتطلّب منك المستوى 2 تغييرها إلى child-src. لم يعد هذا ضروريًا في المستوى 3 من سياسة أمان المحتوى.

  • يحتوي زر أعجبني في Facebook على عدد من خيارات التنفيذ. ننصح بالالتزام بإصدار <iframe> لأنه تتم حمايته بأمان من بقية صفحات موقعك الإلكتروني. ويتطلب الأمر توجيه child-src https://facebook.com ليعمل بشكل سليم. يُرجى العِلم أنّ رمز <iframe> الذي يوفّره Facebook يؤدي تلقائيًا إلى تحميل عنوان URL نسبي هو //facebook.com. عليك تغيير ذلك لتحديد HTTPS بوضوح: https://facebook.com. ولا يُسمَح باستخدام بروتوكول HTTP إذا لم تضطر إلى ذلك.

  • يعتمد زر التغريدة في Twitter على إمكانية الوصول إلى نص برمجي وإطار، وكلاهما مستضاف على https://platform.twitter.com. (يوفر Twitter كذلك عنوان URL نسبي بشكل تلقائي، ويمكنك تعديل الرمز لتحديد HTTPS عند نسخه/لصقه محليًا). ستكون جاهزًا لاستخدام script-src https://platform.twitter.com; child-src https://platform.twitter.com طالما أنّك تنقل مقتطف JavaScript الذي يوفّره Twitter إلى ملف JavaScript خارجي.

  • للمنصات الأخرى متطلبات مماثلة، ويمكن معالجتها بالطريقة نفسها. نقترح فقط ضبط default-src لـ 'none'، ومشاهدة وحدة التحكّم لتحديد الموارد التي ستحتاج إلى تفعيلها لتفعيل التطبيقات المصغّرة.

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

script-src https://apis.google.com https://platform.twitter.com; child-src https://plusone.google.com https://facebook.com https://platform.twitter.com

حالة الاستخدام رقم 2: الإغلاق

افترض لوهلة أنك تدير موقعًا مصرفيًا وتريد التأكد من أنه لا يمكن تحميل سوى الموارد التي كتبتها بنفسك. في هذا السيناريو، ابدأ بسياسة تلقائية تحظر كل شيء (default-src 'none') تمامًا، ثم بناء من هناك.

لنفترض أنّ المصرف يحمِّل جميع الصور والأنماط والنصوص البرمجية من شبكة توصيل للمحتوى في https://cdn.mybank.net، ويتصل عبر XHR بـ https://api.mybank.com/ لسحب أجزاء مختلفة من البيانات. ويتم استخدام الإطارات، ولكن فقط للصفحات المحلية على الموقع الإلكتروني (وليست مصادر تابعة لجهات خارجية). لا يوجد Flash على الموقع، ولا خطوط أو عناصر إضافية. أكثر عناوين سياسة أمان المحتوى تقييدًا التي يمكننا إرسالها هي:

Content-Security-Policy: default-src 'none'; script-src https://cdn.mybank.net; style-src https://cdn.mybank.net; img-src https://cdn.mybank.net; connect-src https://api.mybank.com; child-src 'self'

حالة الاستخدام رقم 3: طبقة المقابس الآمنة فقط

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

Content-Security-Policy: default-src https:; script-src https: 'unsafe-inline'; style-src https: 'unsafe-inline'

على الرغم من تحديد https: في default-src، لا تكتسب توجيهات النص البرمجي والنمط ذلك المصدر تلقائيًا. يستبدل كل توجيه المسار الافتراضي لهذا النوع المحدد من الموارد تمامًا.

المستقبل

المستوى 2 من سياسة أمان المحتوى هو اقتراح للمرشحين. لقد بدأت مجموعة عمل أمان تطبيقات الويب التابعة لـ W3C العمل على التكرار التالي للمواصفات، وهو المستوى 3 لسياسة أمان المحتوى.

إذا كنت مهتمًا بالمناقشة حول هذه الميزات القادمة، فتخطَّ أرشيفات القائمة البريدية public-webappsec@ أو انضم بنفسك.

إضافة ملاحظات