Rudra Analyzer

الأمان

شرح Content-Security-Policy: التوجيهات، و unsafe-inline، و nonce، وتطبيق آمن

CSP أقوى ترويسات الأمان وأسهلها وقوعًا في الخطأ. التوجيهات المهمة، وكيف يحل nonce و hash محل 'unsafe-inline'، وخطة تطبيق لا تعطّل موقعك.

بقلم Rudra Techno Team 8 دقائق للقراءة
في هذه الصفحة

Content-Security-Policy (واختصارها CSP) ترويسة استجابة تخبر المتصفح بالمصادر التي يجوز للصفحة أن تحمّل منها السكربتات والأنماط والصور والإطارات وسائر الموارد. ومهمتها الأساسية الحدّ من الضرر: إن نجح مهاجم في حقن <script> في صفحتك عبر ثغرة برمجة عبر المواقع (XSS)، منعت السياسة الجيدة المتصفح من تشغيله.

المشكلة أن «وجود CSP» و«وجود CSP جيدة» أمران مختلفان جدًّا. فترويسة مليئة بأحرف البدل تجتاز فحص الوجود ولا تكاد تحمي شيئًا. يشرح هذا الدليل كيف تميّز بينهما.

كيف تُبنى السياسة

السياسة قائمة من التوجيهات تفصل بينها فواصل منقوطة. وكل توجيه يسمّي نوعًا من الموارد والمصادر المسموح بها له: Content-Security-Policy: default-src 'self'; img-src 'self' https://images.example-cdn.com; object-src 'none'.

قد تكون المصادر 'self' (أصل موقعك)، أو أصولًا محددة مثل https://js.stripe.com، أو مخططات مثل https: أو data:، أو كلمات مفتاحية مثل 'none'، أو قيم nonce و hash التي يأتي شرحها بعد قليل. الكلمات المفتاحية تُكتب بين علامتَي اقتباس مفردتين؛ والأصول تُكتب بدونهما.

أهم التوجيهات

  • default-src: القيمة الاحتياطية لمعظم أنواع الموارد التي لا تذكرها منفردة.
  • script-src: المصادر التي يجوز أن تأتي منها السكربتات. هذا هو التوجيه الذي يتصدى فعلًا لهجمات XSS، فهو الأحق بالعناية.
  • style-src و img-src و font-src و connect-src (لطلبات fetch و XHR و WebSockets) و frame-src و media-src: بقية أنواع الموارد.
  • object-src 'none': يحظر الإضافات مثل <object> و <embed>، وهي طريق قديم لتنفيذ السكربتات ما زال يُستشهد به.
  • base-uri 'self' أو 'none': يمنع وسم <base> المحقون من تغيير الوجهة التي تشير إليها عناوين السكربتات النسبية.
  • frame-ancestors: المواقع التي يجوز لها تضمين صفحتك داخل إطار، وهو البديل الحديث من X-Frame-Options.
  • form-action: الوجهات التي يجوز أن تُرسَل إليها النماذج.
  • upgrade-insecure-requests: يطلب من المتصفح تحميل الموارد الفرعية ذات العنوان http:// عبر HTTPS.
  • report-to / report-uri: الوجهة التي يرسل إليها المتصفح تقارير المخالفات.

ما الذي يُضعف السياسة

'unsafe-inline'

في script-src، تسمح 'unsafe-inline' بكل كتلة <script> مضمّنة وبكل معالج أحداث مضمّن مثل onclick. وهذا بالضبط ما يحقنه هجوم XSS، فالسياسة التي تسمح للسكربتات بـ 'unsafe-inline' لا تكاد تعرقله. والمتصفحات التي تدعم nonce أو hash تتجاهل 'unsafe-inline' عند وجود أحدهما، ولهذا تُترك أحيانًا مع nonce قيمة احتياطية للمتصفحات القديمة جدًّا.

'unsafe-eval'

'unsafe-eval' تسمح بـ eval() و new Function() وبتمرير سلاسل نصية إلى setTimeout. وهي تحوّل البيانات إلى شيفرة، وفي ذلك خطر. بعض المكتبات ومحركات القوالب القديمة تحتاج إليها؛ أما البنى الحديثة فلا تحتاج إليها في العادة.

المصادر الواسعة

* أو https: أو http: أو data: في script-src تسمح بالسكربتات من أي مكان تقريبًا، فيستطيع المهاجم استضافة سكربته على أي خادم HTTPS. وشبكات CDN الشائعة مشكلة أخفى: السماح بمضيف CDN عام بأكمله يتيح للمهاجم تحميل أي مكتبة مستضافة عليه، ومنها إصدارات قديمة معروفة بطرق الالتفاف عليها.

الاكتفاء بوضع Report-Only

Content-Security-Policy-Report-Only تبلّغ عن المخالفات لكنها لا تحظر شيئًا. هي الطريقة الصحيحة للبدء، والموضع الخاطئ للتوقف.

قيم nonce و hash: المخرج من 'unsafe-inline'

nonce قيمة عشوائية يولّدها خادمك مع كل استجابة. تضعها في الترويسة، هكذا: script-src 'nonce-R4nd0mV4lue'، وفي كل وسم سكربت تثق به: <script nonce="R4nd0mV4lue">. ولا يشغّل المتصفح إلا السكربتات التي تحمل القيمة المطابقة. والسكربت المحقون لا يعرف القيمة، فيُحظر. يجب أن تكون القيمة غير قابلة للتوقع ومختلفة في كل استجابة؛ فالقيمة الثابتة ليست أفضل من 'unsafe-inline'.

أما hash فيسمح بسكربت مضمّن واحد بعينه عبر تجزئة محتواه بخوارزمية SHA-256 أو SHA-384 أو SHA-512: script-src 'sha256-…'. وهو يناسب الصفحات الثابتة التي لا يكون فيها توليد nonce مع كل استجابة عمليًّا؛ وأي تغيير في السكربت يغيّر قيمة التجزئة.

إضافة 'strict-dynamic' تتيح للسكربتات التي وثقت بها عبر nonce أو hash أن تحمّل سكربتات أخرى، وتطلب من المتصفحات الداعمة تجاهل قوائم المضيفين المسموح بهم. وبهذا يصبح ما يسمى CSP الصارمة (strict CSP) عمليًّا حتى في المواقع التي تستخدم مديري الوسوم والأدوات المضمّنة: script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none'; base-uri 'none'.

اعرف كيف تُقرأ سياسة CSP لديك

فاحص الأمان المجاني من Rudra يحلل ترويسة Content-Security-Policy لديك توجيهًا توجيهًا، وينبّه إلى 'unsafe-inline' و 'unsafe-eval' ومصادر السكربتات الواسعة وغياب object-src أو base-uri.

يفحص صفحتك الرئيسية · مجاني · دون تسجيل

خطة تطبيق لا تعطّل موقعك

  1. احصر ما تحمّله الصفحة. افتح أدوات المطوّر في صفحاتك الأساسية، أي الرئيسية وتسجيل الدخول وإتمام الشراء والصفحات التي فيها محتوى مضمّن، ودوّن كل أصل لسكربت أو نمط أو خط أو إطار أو API.
  2. أرسل سياسة Report-Only. ابدأ بشيء مثل default-src 'self'; script-src 'self' 'nonce-{random}'; object-src 'none'; base-uri 'self' في ترويسة Content-Security-Policy-Report-Only. تظهر المخالفات في كونسول المتصفح، وفي نقطة استقبال التقارير إن حددت واحدة.
  3. أصلح كل مخالفة أو اسمح بها. انقل السكربتات المضمّنة إلى ملفات أو امنحها nonce، واستبدل بمعالجات onclick المضمّنة addEventListener، وأضف أصول الأطراف الثالثة التي تستخدمها فعلًا دون غيرها.
  4. افرض السياسة. حين تهدأ التقارير في مساراتك الأساسية كلها، غيّر اسم الترويسة إلى Content-Security-Policy. ولك أن تواصل إرسال سياسة Report-Only أشد صرامة إلى جانبها لاختبار الخطوة التالية.
  5. واظب على صيانتها. كل أداة مضمّنة أو أداة تحليلات أو مزوّد دفع جديد يستلزم تعديلًا في السياسة. أعد الفحص بعد إضافة أي منها.

اضبط الترويسة في الخادم أو CDN أو إطار العمل، لا في وسم <meta> ما استطعت تجنب ذلك: فالسياسة المكتوبة في وسم meta لا تستطيع استخدام frame-ancestors ولا التقارير ولا وضع Report-Only.

ما الذي يفحصه Rudra في سياستك

فاحص أمان المواقع المجاني يقرأ CSP التي ترسلها صفحتك فعلًا ويعرض التوجيهات بعد تحليلها دليلًا على ما وجده. وينبّه إلى غياب السياسة، وإلى سياسة تُرسَل في وضع Report-Only فقط، وإلى سياسة لا تقيّد السكربتات إطلاقًا (بلا script-src ولا default-src)، وإلى 'unsafe-inline' في سياسة السكربتات (ولا ينبّه إليها عند وجود nonce أو hash)، وإلى 'unsafe-eval'، وإلى مصادر السكربتات الواسعة مثل * أو https: (ما لم تستخدم 'strict-dynamic' مع nonce أو hash)، ويذكر في ملاحظات إعلامية غياب object-src 'none' وغياب base-uri ووجود الأنماط المضمّنة. ويعدّ frame-ancestors حماية من اختطاف النقرات ما لم تكن قيمته * أو مخططًا مجردًا.

أداة الفحص تخبرك بما تسمح به سياستك. لكنها لا تخبرك هل ما زالت صفحاتك تعمل في ظلها؛ لا يخبرك بذلك إلا اختبار مساراتك الحقيقية في وضع التقرير فقط.

الأسئلة الشائعة

هل تمنع Content-Security-Policy هجمات XSS؟

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

هل وجود 'unsafe-inline' في style-src مشكلة؟

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

هل أستطيع استخدام قيمة nonce نفسها في كل الصفحات؟

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

كم ينبغي أن أشغّل وضع Report-Only قبل فرض السياسة؟

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

هل تحتاج إلى تحليل أعمق لموقعك؟

اطّلع على كل مشكلة في موقعك مرتبةً حسب أولوية الإصلاح

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