سياسة CSP حجبت محرر ووردبريس؟ الحل دون إضعاف الحماية

درع زجاجي أمام نافذة متداخلة يرمز إلى سياسة أمان المحتوى CSP في محرر ووردبريس

تخيل إنك ضفت طبقة حماية جديدة لمواقع عملائك، وبعد كام يوم العميل يكلمك: «بدخل عادي، بس أول ما أفتح أي ووردبريس للمحتوى المؤرخ مثل التدوينات والأخبار والشروحات. تُرتّب زمنيًا وتُنظَّم بالتصنيفات والوسوم وتظهر في الأرشيف وخلاصات RSS، بخلاف الصفحات الثابتة.">صفحة أعدلها الشاشة بتبقى فاضية ومكتوب This content is blocked». ده بالظبط اللي حصل لمطور بيدير ثماني مواقع، والحماية ما كانش فيها عيب. كانت شغالة بزيادة لدرجة إنها حمت الموقع من شاشة التحرير بتاعته.

ما الذي حدث بالضبط؟

الحماية المقصودة هي سياسة أمان المحتوى (Content Security Policy)، أو السيرفر للمتصفح مع كل صفحة، مثل HSTS وX-Content-Type-Options، لمنع هجمات شائعة في المتصفح. تكلفتها صفر، لكن Content Security Policy يحتاج اختبارًا مع منشئات الصفحات.">CSP اختصاراً. هي ترويسة يرسلها السيرفر مع كل صفحة، وتعمل كقائمة ضيوف: من أين يُسمح بتحميل السكربتات والصور والخطوط والإطارات. أي مصدر خارج القائمة لا يُحمَّل.

الهدف منها صد عائلة كاملة من الهجمات، أشهرها حقن السكربتات عبر المواقع (XSS)، حين ينجح مهاجم في زرع كود داخل صفحتك.

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

خطوة 1: اعرف التوجيه الذي يحجب المحرر

لا تخمّن. افتح صفحة التحرير، ثم أدوات المطور في المتصفح (F12)، وانتقل إلى تبويب Console. ستجد رسالة تذكر اسم التوجيه المخالف، مثل frame-src أو child-src، والمصدر الذي حُجب.

في الحالة الموصوفة كان المصدر المحجوب إطاراً يولّده كود الصفحة نفسها في الذاكرة، وهذا النوع يظهر في المتصفح بعنوان يبدأ بـ blob:. رسالة الـ Console عندك هي المرجع، فقد يختلف المصدر حسب إصدار ووردبريس والإضافات.

خطوة 2: الحل السهل هو الحل الخاطئ

أسرع حل هو تعطيل CSP بالكامل داخل /wp-admin/. سيعمل خلال دقيقة، لكنه يزيل الحماية عن أثمن جزء في الموقع، وهو الجزء الذي يستهدفه المهاجم أولاً.

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

# .htaccess — example policy, adapt sources to your own site
<IfModule mod_headers.c>
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; frame-src 'self' blob:; worker-src 'self' blob:; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"
</IfModule>

إضافة blob: إلى frame-src لا تفتح باباً للمهاجم الخارجي، لأن روابط blob: لا ينشئها إلا كود يعمل داخل صفحتك أصلاً.

خطوة 3: استغل الفرصة لإحكام القفل

أثناء الإصلاح أضاف المطور ثلاثة توجيهات كانت ناقصة، فخرج الموقع أكثر صرامة لا أقل:

التوجيهما يمنعه
object-src 'none'محتوى الإضافات القديمة مثل Flash وعناصر <object>
——
base-uri 'self'تغيير العنوان الأساسي للصفحة لتحويل الروابط النسبية إلى موقع آخر
worker-src 'self' blob:تشغيل عمّال الخلفية (Web Workers) من مصادر غريبة

انتبه لصفحة الدفع قبل أي قاعدة إضافية

هناك توجيه مغرٍ اسمه form-action، يحدد الجهات التي يُسمح للنماذج بإرسال بياناتها إليها. لكن إن كان متجرك يحوّل العميل إلى صفحة بوابة الدفع (Payment Gateway) لإتمام العملية، فقد يكسر هذا التوجيه الدفع بصمت.

في مصر تحديداً، بوابات مثل Paymob وKashier قد تعرض نموذج البطاقة داخل iframe أو تحوّل العميل إلى نطاقها. أضف نطاقات البوابة التي تستخدمها إلى frame-src (وإلى form-action إن فعّلته)، ثم نفّذ طلب شراء تجريبياً كاملاً. قاعدة أمان تمنع العميل من الدفع ليست مكسباً.

في القالب كاملًا والنماذج والنوافذ المنبثقة.">Elementor: محرر Elementor يعرض صفحتك نفسها داخل iframe من الدومين ذاته. لذلك لا تضبط frame-ancestors على 'none' ولا ترسل X-Frame-Options: DENY، وإلا ستظهر شاشة تحميل لا تنتهي في المحرر. القيمة 'self' تحمي الموقع من التضمين في مواقع أخرى وتُبقي المحرر يعمل.

جرّب أولاً بوضع التقرير فقط

أذكى طريقة لتفادي هذا الموقف كله أن تبدأ بـ وضع التقرير فقط (Report-Only Mode). أرسل السياسة الجديدة في ترويسة Content-Security-Policy-Report-Only بجانب السياسة الحالية لبضعة أيام. سيسجّل المتصفح في الـ Console كل ما كان سيحجبه، ومنه إطار المحرر، دون أن يتعطل شيء.

Header always set Content-Security-Policy-Report-Only "default-src 'self'; frame-src 'self'; object-src 'none'; base-uri 'self'"

إن كنت تدير أكثر من موقع

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

curl -sI https://example.com/wp-admin/ | grep -i content-security-policy

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

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

س: ما معنى رسالة This content is blocked في محرر ووردبريس؟
ج: غالباً أن سياسة CSP أو ترويسة X-Frame-Options تمنع المتصفح من عرض الإطار الداخلي للمحرر. راجع الـ Console لمعرفة التوجيه المسؤول.

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

س: هل تعطيل CSP في لوحة التحكم حل مقبول؟
ج: لا. لوحة التحكم هي أهم ما تحميه السياسة. أضف المصدر المحدد الذي يحتاجه المحرر بدلاً من إزالة الحماية كلها.

س: هل يمكن ضبط CSP بإضافة بدل تعديل .htaccess؟
ج: نعم، بعض إضافات الأمان وترويسات HTTP تتيح ذلك، كما يمكن ضبطها عبر Cloudflare. المهم أن تختبر المحرر وصفحة الدفع بعد كل تعديل.

الخلاصة

الحماية الشديدة اللي بتقفل الباب في وشك مش حماية، دي عطل. ابدأ دايماً بوضع التقرير فقط، وصلّح السطر اللي ناقص بدل ما تشيل الحماية كلها، وبعد كل تعديل افتح صفحة واعملها تعديل وحفظ بنفسك.

مرجع المقال (بالإنجليزية): My Security Upgrade Locked a Client Out of Editing Their Own Website
المقال ده مش ترجمة حرفية: متكيّف للقارئ العربي ومضاف عليه سياق ووردبريس وElementor وJetEngine.

اترك تعليقاً