ديسكورش + جدار حماية تطبيقات الويب (WAF) mod_security

ما هو جدار حماية تطبيقات الويب (WAF) الموصى به للعمل أمام Discourse؟

نجحت مؤخرًا في تعديل ملف إعدادات nginx المثبت داخل حاوية Docker الخاصة بـ Discourse لتشمل ModSecurity ومجموعة قواعد OWASP (مشروع أمان تطبيقات الويب المفتوح) CRS (مجموعة القواعد الأساسية).

حتى الآن، كانت اختباراتي ممتازة، ويبدو أن ModSecurity يتفاعل بشكل ممتاز مع Discourse من دون إعدادات إضافية.

ما هي تجارب المستخدمين الآخرين مع جدران حماية تطبيقات الويب وDiscourse؟ هل لديك أي توصيات بخلاف ModSecurity؟

ملاحظة حول أهمية جدران حماية تطبيقات الويب (WAFs): فهي توفر حماية واسعة ضد الثغرات الصفرية (0days) لا فقط من تطبيق الويب نفسه، بل أيضًا من كامل مجموعة تبعياته.

تم التنبيه إليّ بأن فريق Discourse لديه برنامج مكافآت للأخطاء (bug bounty program)، وهو أمر رائع!

…لكن، بطبيعة الحال، لا يوجد شيء اسمه كود آمن بنسبة 100%. الأخطاء تحدث، ولا يشترط حتى أن تكون خطأً من فريقك لإدخال ثغرة حرجة في مشروعك.

على سبيل المثال، انظر إلى التاريخ الحديث مع CVE-2019-11043: خطأ في php-fpm يمكن استغلاله لتنفيذ أكواد عن بعد على الخوادم التي تعمل بإصدارات ضعيفة من php-fpm و nginx.

ومع ذلك، يمكن التخفيف من CVE-2019-11043 كاملًا عن طريق حظر الطلبات التي تتضمن إرجاعًا للكارية (carriage return) أو سطورًا جديدة:

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

في الحالة المذكورة أعلاه، ومع ذلك، فإن ModSecurity CRS يُحظر بالفعل الطلبات التي تحتوي على سطور جديدة وإرجاعات للكارية—مما يحمي فعليًا خوادم الويب التي قد تكون عرضة للخطر تجاه CVE-2019-11043 قبل اليوم صفر.

مثل هذه الثغرات تُكتشف دائمًا. هناك فوائد كبيرة لاستخدام جدار حماية تطبيقات ويب مثل ModSecurity لتطبيقات الويب.

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

ذو صلة: لقد وجدت للتو هذا الدليل من @joelradon حول كيفية تثبيت Discourse مع NAXSI WAF في nginx قبل حاوية Docker الخاصة بـ Discourse:

لا يمكن دعمه أكثر مما تطلبه أعلاه.

إذا كان ذلك سيساعد، يمكنني إضافة علامة “غير مدعوم” هناك أيضًا؟

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

بالطبع، إذا كنت تشغّل برنامجًا تم استغلاله قبل سنوات ولا تملك حرية الترقية لأسباب… فإن جدار حماية تطبيقات الويب (WAF) يكون منطقيًا لأنه قد ينقذك. لكن في حالة Discourse، أعتقد أن هذا الأمر في أحسن الأحوال مضلل.

تمكنت بنجاح من الاحتفاظ بتغييرات إعدادات nginx ModSecurity عبر عمليات تشغيل launcher rebuild app على النحو التالي:

أولاً، قمنا بتحديث النسخة المحلية من install-nginx التي أتت من مستودع discourse_docker وتم استنساخها إلى /var/discourse/.

cd /var/discourse/image/base
cp install-nginx install-nginx.`date "+%Y%m%d_%H%M%S"`.orig

# إضافة كتلة لاستخراج وحدة ModSecurity لـ nginx مباشرة قبل تنزيل مصدر nginx
grep 'ModSecurity' install-nginx || sed -i 's%\(curl.*nginx\.org/download.*\)%# mod_security\napt-get install -y libmodsecurity-dev modsecurity-crs\ncd /tmp\ngit clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git\n\n\1%' install-nginx

# تحديث سطر التكوين ليشمل وحدة ModSecurity المستخرجة أعلاه
sed -i '/ModSecurity/! s%^[^#]*./configure \(.*nginx.*\)%#./configure \1\n./configure \1 --add-module=/tmp/ModSecurity-nginx%' install-nginx

# إضافة سطر إلى قسم التنظيف
grep 'rm -fr /tmp/ModSecurity-nginx' install-nginx || sed -i 's%\(rm -fr.*/tmp/nginx.*\)%rm -fr /tmp/ModSecurity-nginx\n\1%' install-nginx

لاحظ أن ملف Dockerfile المسؤول عن تنفيذ سكريبت install-nginx يتم تنفيذه عند بناء الصورة. ويتم بناء الصورة فقط بواسطة فريق Discourse قبل رفعها إلى docker hub. عند تشغيل أمر Discourse ./launcher rebuild app، يتم تفعيل (إذا كانت هناك تحديثات متاحة) أمر docker pull، الذي يجلب أحدث صورة Docker الخاصة بـ Discourse من docker hub. مرة أخرى، هذا لا يعيد بناء الصورة، ولا ينفذ ملف Dockerfile، ولا ينفذ سكريبت install-nginx الذي تم تعديله أعلاه.

الطريقة الوحيدة (التي أعرفها) لتفعيل تشغيل سكريبت bash المحدّث install-nginx (والذي يتم تنفيذه بواسطة Dockerfile) هي أن يقوم docker ببناء صورة جديدة. على سبيل المثال، هذا يؤدي إلى بناء docker صورة جديدة باسم discourse_modsecurity — والتي سيتم بناؤها باستخدام سكريبت install-nginx المعدّل محليًا:

docker build --tag 'discourse_modsecurity' /var/discourse/image/base/

للأسف، لم أستطع إيجاد طريقة لإخبار launcher باستخدام صورة مخصصة (تحديد run-image يستخدم الصورة المحددة مباشرة، دون تنفيذ القوالب عليها — كما هو مطلوب لتكوين nginx فعليًا [وليس مجرد تثبيته]). لذا قمنا باستبدال متغير image المحدد في سكريبت launcher لاستخدام صورتنا المحلية الجديدة باسم discourse_modsecurity:

# استبدال السطر "image="discourse/base:<version>" بـ 'image="discourse_modsecurity"'
grep 'discourse_modsecurity' launcher || sed --in-place=.`date "+%Y%m%d_%H%M%S"` '/base_image/! s%^\(\s*\)image=\(.*\)$%#\1image=\2\n\1image="discourse_modsecurity"%' /var/discourse/launcher

الآن نضيف ملف قالب جديد لإعداد إعدادات nginx الخاصة بنا لتشمل ملفات/كتل modsecurity الضرورية:

cat << EOF > /var/discourse/templates/web.modsecurity.template.yml
run:
  - exec:
     cmd:
       - sudo apt-get install -y modsecurity-crs
       - cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf
       - sed -i 's/SecRuleEngine DetectionOnly/SecRuleEngine On/' /etc/modsecurity/modsecurity.conf
       - sed -i 's^\(\s*\)[^#]*SecRequestBodyInMemoryLimit\(.*\)^\1#SecRequestBodyInMemoryLimit\2^' /etc/modsecurity/modsecurity.conf
       - sed -i '/nginx/! s%^\(\s*\)[^#]*SecAuditLog \(.*\)%#\1SecAuditLog \2\n\1SecAuditLog /var/log/nginx/modsec_audit.log%' /etc/modsecurity/modsecurity.conf

  - file:
     path: /etc/nginx/conf.d/modsecurity.include
     contents: |
        ################################################################################
        # File:    modsecurity.include
        # Version: 0.1
        # Purpose: Defines mod_security rules for the discourse vhost
        #          This should be included in the server{} blocks nginx vhosts.
        # Author:  Michael Altfield <michael@opensourceecology.org>
        # Created: 2019-11-12
        # Updated: 2019-11-12
        ################################################################################
        Include "/etc/modsecurity/modsecurity.conf"
        
        # OWASP Core Rule Set, installed from the 'modsecurity-crs' package in debian
        Include /etc/modsecurity/crs/crs-setup.conf
        Include /usr/share/modsecurity-crs/rules/*.conf

  - replace:
     filename: "/etc/nginx/conf.d/discourse.conf"
     from: /server.+{/
     to: |
       server {
         modsecurity on;
         modsecurity_rules_file /etc/nginx/conf.d/modsecurity.include;

EOF

وأضفنا هذا القالب (templates/web.modsecurity.template.yml) إلى كتلة القوالب في ملف تكوين yaml الخاص بتطبيقنا ليصبح الشكل كالتالي:

[root@osestaging1 discourse]# vim /var/discourse/containers/app.yml
...
[root@osestaging1 discourse]# grep -A 6 'templates:' /var/discourse/containers/app.yml
templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
  - "templates/web.socketed.template.yml"
  - "templates/web.modsecurity.template.yml"
[root@osestaging1 discourse]# 

الآن عند إعادة بناء تطبيق Discourse docker، سيتم استخدام صورتك الجديدة discourse_modsecurity باستخدام nginx مع modsecurity، وسيتم تكوين nginx لاستخدام OWASP CRS.

/var/discourse/launcher rebuild app

أوافقك الرأي تمامًا على أن ModSecurity أو جدران الحماية لتطبيقات الويب (WAFs) المماثلة ليست حلاً سحريًا.

لكنني أعرف (على الأقل؟) ثغرة أمنية تم اكتشافها في RoR وأثرت على Discourse كان من الممكن التخفيف منها باستخدام آلية شبيهة بـ ModSecurity.

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

لكنني لست متأكدًا مما إذا كانت التعقيدات المضافة تفوق الأمان الإضافي الذي توفره.

أشبه جدران حماية تطبيقات الويب (WAFs) بماسحات الفيروسات المعتمدة على التوقيعات، والتي أرى شخصيًا أنها ليست مفيدة جدًا في البيئات ذات سطح الهجوم المحدود (مثل خوادمك غير Windows).

لن تتمكن من التقاط كل شيء، لكنها ستقوم (نظريًا) باكتشاف الأنماط الشائعة للهجمات (مثل حقن SQL) والاستغلالات المعروفة (مثل ثغرة RoR المذكورة أعلاه) عبر مجموعة من البرامج.

أستطيع أن أرى قيمة تشغيلها خاصة في بيئة (مؤسسية) حيث لديك عدد هائل من التطبيقات تعمل بأشياء لا أحد يعرفها بالضبط، وتحتاج إلى التأكد من حماية كل تطبيق من هذه الاستغلالات دون الحاجة للقلق بشأن كل تطبيق على حدة - وهذا يحول مشكلة بحجم NxM إلى مشكلة بحجم N+M.

سواء كان تشغيلها على موقعك يستحق الأمر أم لا هو مسألة أخرى، وهي من تلك التحليلات بين المخاطر (في حال حدوث خلل) والفوائد (في مجال الحماية) التي ستحتاج إلى إجرائها بنفسك.