تتعرّض جميع الخدمات التي يتم تقديمها عبر الإنترنت لمختلف أنواع الهجمات من قبل أطرافٍ مُسيئة. فإذا كانت الخدمة تتطلب تسجيل دخول (أو ما يُعرف بالتوثيق أو المُصادقة)؛ فسيحاول بعض المستخدمين غير الشرعيين أو برمجيات bot الخبيثة الولوج إلى الخدمة من خلال تكرار محاولات المُصادقة بتجريب بيانات تسجيلٍ مختلفة في كلّ مرة.
من الأمثلة الشائعة على ذلك الهجمات التي تتعرض لها خدمة SSH من قبل شبكة الروبوت Botnet لتجريب أسماء حسابات شائعة بشكل آلي بهدف اختراق الخدمة، إلا أنّه لحسن الحظّ فقد تمّ إنشاء عدّة خدمات مثل fail2ban لمساعدتنا على التخفيف من هذه الهجمات.
يعمل fail2ban عن طريق تعديل قواعد جدار النار بشكل حيوي لحظر العناوين التي تحاول تسجيل الدخول بعد عددٍ مُحدّدٍ من المرات الفاشلة.
في هذا الدرس سنُناقش بمزيدٍ من التعمق كيفيّة عمل الأداة fail2ban وكيف يمكننا تعديل سلوكها لتتوافق مع متطلباتنا.
المفهوم الأساسي
الفكرة الأساسية في عمل fail2ban هي مراقبة سجلات logs الخدمات الشائعة لرصد محاولات تسجيل الدخول الفاشلة.
عندما يُضبط fail2ban لمراقبة سجل خدمة ما، فإنه يبحث في مُرشّح filter مُخصّص لهذه الخدمة. يتم تصميم المُرشِّح لتعريف حالة "فشل المُصادقة" لهذه الخدمة باستخدام تعابير نمطيّة مُعقّدة Regular Rxpressions تُعرّف متغيرًا يُدعى failregex.
لحُسن الحظ يأتي fail2ban مع مجموعة مُرشحات جاهزة للخدمات الأكثر شيوعًا. عندما يطابق سطر ما من سجل الخدمة المُراقبة المُتغيّر failregex من المُرشّح؛ يتم تنفيذ الإجراءات المُحدّدة لهذه الخدمة، والتي يمكن ضبطها للقيام بأشياء مختلفة اعتمادًا على ما يفضّله مُدير الخادوم.
الإجراء الافتراضي الذي يتمّ تنفيذه عادةً هو حظر عنوان الـ IP المُسيء عن طريق تعديل قواعد iptables لجدار الحماية. يمكنك أيضًا توسيع هذا الإجراء لإرسال بريد إلكتروني إلى مدير الخادوم مع تقرير whois عن المهاجم، أو إرفاق الأسطر التي أدّت إلى إطلاق إجراءات الحماية من سجل الخدمة.
يمكن كذلك تعديل إجراءات الحماية لتنفيذ أوامر مختلفة عن سلوك iptables المُعتاد، إذ يمكنك اختيار أوامر أكثر تعقيدًا أو أبسط كما تريد، بالإضافة إلى ملفات الضبط الخاصة بجدار الحماية، وخيارات التنبيه المتاحة.
بشكل افتراضي يتم تنفيذ إجراءات الحماية عند الكشف على ثلاث محاولات تسجيل دخول فاشلة خلال عشرة دقائق، ويكون وقت الحظر الافتراضي هو عشرة دقائق أيضًا. العدد الافتراضي لمحاولات المُصادقة الفاشلة ضروريّ لتفعيل الحظر على جانب SSH إلا أنّه يمكن تعديل ملف الضبط من قبل مدير الخادوم ورفع عدد المحاولات اللازمة لتشغيل إجراءات الحماية إلى ست مرات مثلًا.
عند استخدام أسلوب iptables الافتراضي لحماية حركة SSH، تُنشئ الأداة fail2ban سلسلة جديدة عند بدء الخدمة، مُضيفةً قاعدة جديدة إلى سلسلة الإدخال INPUT chain والتي تُرسل حركة مرور البيانات TCP الموجّهة عند المنفذ 22 إلى السلسلة الجديدة. في السلسلة الجديدة تُضاف قاعدة مُفردة مُعيدةً الحركة إلى سلسلة الإدخال INPUT chain.
هذا ما يجعل حركة البيانات تقفز إلى السلسلة الجديدة أولًا ومن ثم تقفز عائدةً، ورغم أن ذلك لا يؤثر على حركة مرور البيانات بدايةً إلا أنه مع تكرار عنوان IP ما لعملية المُصادقة عدّة مرات ووصوله إلى عتبة "فشل المصادقة"؛ تُضاف قاعدة إلى بداية السلسلة الجديدة لمنع حركة المرور الصادرة من عنوان IP المُسيء، والذي يؤدي إلى حظره فورًا. بعد انتهاء فترة الحظر تُحذف القاعدة من iptables، ويتم إزالة السلسلة والقواعد المرتبطة بها عند انتهاء خدمة fail2ban.
استعراض إعدادات خدمة Fail2ban
يتم ضبط fail2ban من خلال مجموعة متنوعة من الملفات الموجودة ضمن الدليل /etc/fail2ban/ والمرتبة بشكلٍ هرمي.
فعلى سبيل المثال يضبط الملف fail2ban.conf بعض إعدادات التشغيل الأساسية مثل طريقة daemon في تسجيل المعلومات وكيفيّة استخدام المقابس socket وملفات pid. بكل الأحوال فإن الإعدادات الرئيسية تُحفظ في ملفات تُدعى "jails".
بشكل افتراضي يأتي fail2ban مع الملف jail.conf والذي يُستبدل عادةً مع كلّ تحديث، لذا يُنصح المستخدمون بنسخ هذا الملف تحت اسم jail.local وإجراء التعديلات هناك.
إذا كنت تملك بالفعل الملف jail.local افتحه على الفور باستخدام محرّر نصيّ:
sudo nano /etc/fail2ban/jail.local
أما إذا لم يكن الملف موجودًا بالفعل أو كان فارغًا بعد فتحه؛ انسخه من جديد باسم jail.local ثم افتحه بمحرّر نصيّ:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local sudo nano /etc/fail2ban/jail.local
لنُلقي نظرة على الخيارات المتاحة هنا ونرى كيف يتفاعل هذا الملف مع ملفات الضبط الأخرى ضمن النظام.
القسم الافتراضي
يُعرّف الجزء الأول من الملف القيم الافتراضية لآلية عمل fail2ban. يمكن تجاوز هذه الخيارات من قبل مقاطع الضبط اللاحقة والخاصة بكل خدمة على حدا.
بإهمال التعليقات سيبدو القسم الافتراضي مشابهًا لهذا:
[DEFAULT] ignoreip = 127.0.0.1/8 bantime = 600 findtime = 600 maxretry = 3 backend = auto usedns = warn destemail = root@localhost sendername = Fail2Ban banaction = iptables-multiport mta = sendmail protocol = tcp chain = INPUT action_ = %(banaction)s[name=%(name)s, port=”%(port)s”, protocol=”%(protocol)s”, chain=”%(chain)s”] action_mw = %(banaction)s[name=%(name)s, port=”%(port)s”, protocol=”%(protocol)s”, chain=”%(chain)s”] %(mta)s-whois[name=%(name)s, dest=”%(destemail)s”, protocol=”%(protocol)s”, chain=”%(chain)s”, sendername=”%(sendername)s”] action_mwl = %(banaction)s[name=%(name)s, port=”%(port)s”, protocol=”%(protocol)s”, chain=”%(chain)s”] %(mta)s-whois-lines[name=%(name)s, dest=”%(destemail)s”, logpath=%(logpath)s, chain=”%(chain)s”, sendername=”%(sendername)s”] action = %(action_)s
دعونا نشرح ماذا يعني ذلك في الواقع:
- ignoreip: يُعرّف هذا الخيار مجموعة عناوين IP كقائمة بيضاء يتمّ تجاهلها من قبل نظام الحظر. افتراضيًا يتم تعيين هذا الخيار لتجاهل حركة المرور القادمة من قبل الجهاز نفسه فقط، ومن الجيد أن نُبقي على ذلك.
- bantime: يُحدّد هذا الخيار طول مدّة الحظر بالثواني، وبشكل افتراضي يأخذ القيمة 600 ثانية (أي عشرة دقائق).
- findtime: يُحدّد الفترة الزمنية التي ستتم مراقبتها للنظر في تكرار محاولات تسجيل الدخول الفاشلة. القيمة الافتراضية هي 600 ثانية (أي عشرة دقائق أيضًا)، والذي يعني أن fail2ban سيحسب عدد محاولات الولوج الفاشلة في آخر عشرة دقائق.
- maxretry: يُحدّد عدد محاولات تسجيل الدخول الفاشلة التي سيُحظر بعدها عنوان IP مباشرةً من قبل fail2ban وذلك ضمن الإطار الزمني المُحدّد من قبل findtime.
- backend: يُحدّد هذا الخيار كيف يراقب fail2ban ملفات السجل، فالقيمة auto تعني أن fail2ban سيجرّب أسلوب pyinotify ثم gamin وبعدها يختار خوارزمية بناءً على ما هو متاح.
- usedns: يُحدّد خوادم DNS التي سوف تُستخدم للمساعدة في تنفيذ الحظر. فالقيمة "no" تعني استخدام عناوين IP نفسها في الحظر بدلًا من استعمال اسم المضيف hostnames. بينما تسعى القيمة "warn" إلى الاستفادة من أدلة DNS للبحث عن اسم المضيف وحظره مع تسجيل النشاط للمراجعة.
- destemail: يُوضع هنا عنوان البريد الإلكتروني الذي ستُرسل إشعارات التنبيه إليه (فيما إذا كانت ميزة الإشعارات مُفعّلة).
- sendername: يُحدّد محتوى الحقل "from" في رسائل الإشعارات المولّدة من الخيار السابق.
- banaction: يُعيّن هذا الخيار العمل الذي سيتم تنفيذه حال الوصول إلى عتبه "فشل المُصادقة"، وفي الواقع هناك ملف ضمن الدليل /etc/fail2ban/action.d/ باسم iptables-multiport.conf يُعالج مهمة iptables لحجب عناوين IP، وهو ما سنتطرق إليه لاحقًا.
- mta: وكيل نقل البريد المُستخدم لإرسال التنبيهات البريدية.
- protocol: يُحدّد نوع حركة مرور البيانات التي سيتم إسقاطها عند تنفيذ حظر IP، وكذلك نوع حركة المرور التي سيتم إرسالها إلى سلسلة iptables جديدة.
- chain: وهي السلسلة التي سيتم ضبطها مع قاعدة قفز jump rule لإرسال حركة المرور إلى fail2ban.
باقي المُعاملات تُعرِّف إجراءات مختلفة يمكن تخصيصها. تُمرّر هذه الإجراءات في بعض المُعاملات السابقة من خلال سلسلة استيفاء string interpolation على النحو التالي:
%(var_name)s
في السطر أعلاه يُستبدل محتوى var_name. باتباع هذه الطريقة يتم إسناد المتغيّر action إلى المُعرّف action_ بشكلٍ افتراضي (ما يؤدي إلى تنفيذ الحظر دون إرسال إشعار عبر البريد)، وهذا بدوره يُضبط عبر استدعاء الإجراء iptables-multiport مع قائمة من المُعاملات (مثل اسم الخدمة، المنفذ، البروتوكول، والسلسلة) اللازمة لتنفيذ الحظر. يتم استبدال name مع اسم الخدمة كما هو مُحدّد بواسطة ترويسات الأقسام في الأسفل.
أقسام الخدمات الخاصة
أسفل القسم الافتراضي هناك أقسام مُخصّصة لكل خدمة على حدا والتي يمكن استخدامها لتجاوز الإعدادات الافتراضية، وهذا يتبع للخيارات التي يمكن لها أن تأخذ قيمًا مُختلفة عن القيم العادية.
تُحدّد ترويسة كل مقطع كما يلي:
[service_name]
أي مقطع يحتوي على هذا السطر سيُقرأ ويٌفعّل:
enabled = true
تُضبط المُعاملات ضمن كل قسم بما في ذلك ملف المُرشّح والذي يجب استخدامه لتحليل السجلات ومواقع ملفات السجلات نفسها.
خذ بعين الاعتبار أن المقطع الذي يُحدِّد إجراءات الحماية لخدمة SSH يبدو مثل هذا:
[SSH] enabled = true port = ssh filter = sshd logpath = /var/log/auth.log maxretry = 6
يُفعّل السطر الأول enabled= true القسم الخاص بخدمة SSH ويُعيّن المنفذ إلى منفذ SSH (بالرقم 22) مُخبرًا fail2ban بالنظر إلى السجل var/log/auth.log/ وتحليله باستخدام آليات الترشيح المُحدّدة ضمن الدليل /etc/fail2ban/filters.d/ في الملف المُسمى sshd.conf.
تؤخذ جميع أجزاء المعلومات اللازمة من المُعاملات المُعرّفة ضمن القسم [DEFAULT] . فعلى سبيل المثال يتم تعيين إجراء تنفيذ الخيار action_ والذي يحظر عنوان IP المُسيء باستخدام iptables-multiport والذي يشير إلى الملف iptables-multiport.conf ضمن المسار /etc/fail2ban/action.d/.
وكما ترى يجب أن تكون الإجراءات ضمن المقطع [DEFAULT] عامة ومرنة. الاستخدام المُكثّف لمُعاملات الاستبدال جنبًا إلى جنب مع المُعاملات المزودة بقيم افتراضية معقولة يجعل التعريفات سهلة التجاوز عند الضرورة.
شرح ملف الترشيح
من أجل فهم ما يجري في إعدادات الضبط الخاصة بنا، نحن بحاجة إلى فهم كلًا من ملف المُرشّح filter file وملف الإجراء action file، والتي تُشكّل الجزء الأكبر من العمل.
يُحدّد ملف المُرشّح الأسطر التي يبحث عنها fail2ban في ملفات السجل لتحديد خصائص المُسيء. بينما يُزوّد ملف الإجراء بجميع الإجراءات المطلوبة، من بناء صيغة لجدار الحماية firewall structure عند بدء تشغيل الخدمة، وحتى إضافة وحذف القواعد، علاوةً على إلغاء صيغة جدار الحماية عند توقّف الخدمة.
دعونا ننظر في ملف المُرشّح المدعو بواسطة خدمة SSH لدينا من الإعدادات أعلاه:
sudo nano /etc/fail2ban/filter.d/sshd.conf
[INCLUDES] before = common.conf [Definition] _daemon = sshd failregex = ^%(__prefix_line)s(?:error: PAM: )?[aA]uthentication (?:failure|error) for .* from ( via \S+)?\s*^%(__prefix_line)s(?:error: PAM: )?User not known to the underlying authentication module for .* from \s* ^%(__prefix_line)sFailed \S+ for .? from (?: port \d)?(?: ssh\d*)?(: (ruser .|(\S+ ID \S+ (serial \d+) CA )?\S+ %(__md5hex)s(, client user “.“, client host “.“)?))?\s^%(__prefix_line)sROOT LOGIN REFUSED.* FROM \s* ^%(__prefix_line)siI user .* from \s*^%(__prefix_line)sUser .+ from not allowed because not listed in AllowUsers\s* ^%(__prefix_line)sUser .+ from not allowed because listed in DenyUsers\s*^%(__prefix_line)sUser .+ from not allowed because not in any group\s* ^%(__prefix_line)srefused connect from \S+ ()\s*^%(__prefix_line)sUser .+ from not allowed because a group is listed in DenyGroups\s* ^%(__prefix_line)sUser .+ from not allowed because none of user’s groups are listed in AllowGroups\s*$ ignoreregex =
يبدو هذا مُعقّدًا للغاية، لنبسطّه قليلًا فيما يلي.
يُحدّد المقطع [INCLUDES] الملفات الأخرى التي ستتم قراءتها قبل أو بعد الملف، في مثالنا هذا يُقرأ الملف common.conf وتُوضع محتوياته أمام الأسطر الأخرى من الأصل، وهذا ما يُضيف بعض المعاملات اللازمة لضبط الإعدادات لدينا.
بعد ذلك لدينا المقطع [Definition] والذي يُحدّد القواعد الفعلية لمطابقات المرشّح. بدايةً نُحدّد اسم خدمة daemon المراقبة بواسطة المعامل _daemon.
ومن ثمّ يأتي تعريف المتغيّر failregex المُحدّد بواسطة أنماط تبحث عن أية أسطر مطابقة في ملفات السجل، وهي عبارة عن تعابير نمطيّة Regular Expressions تتطابق مع مختلف الأخطاء والإخفاقات التي يمكن أن تحدث عندما لا تتم مصادقة تسجيل الدخول بشكل صحيح.
فعلى سبيل المثال يُستبدل الجزء prefix_line)s__)% من التعريف السابق مع قيمة معاملات الإعداد من ملف common.conf. يُستخدم هذا التعبير لمطابقة المعلومات التي تكتبها أنظمة التشغيل إلى ملفات السجل عندما تستخدم الأساليب القياسية. فعلى سبيل المثال بعض الأسطر من السجل var/log/auth.log/ قد تبدو مثل هذا:
May 6 18:18:52 localhost sshd[3534]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=101.79.130.213 May 6 18:18:54 localhost sshd[3534]: Failed password for invalid user phil from 101.79.130.213 port 38354 ssh2 May 6 18:18:54 localhost sshd[3534]: Received disconnect from 101.79.130.213: 11: Bye Bye [preauth]
الجزء الملّون بالأحمر يُمثّل نمطًا قياسيًا standard pattern مُدرجًا من قبل نظام التشغيل لدعم السياق context. بعد ذلك هناك عدد غير قليل من الطرق المختلفة التي يمكن لخدمة iptables كتابة محاولات الفشل وفقها إلى السجل.
يحتوي ملف السجل السابق على محاولتي تسجيل دخول فاشلتين في السطرين الأوّل والثاني (إحداهما خطأ مصادقة من نوع PAM والأخرى خطأ كلمة مرور)، يتم تعريف التعابير النمطية في المرشّح لمطابقة أي سطر يحمل رسالة فشل في المصادقة، لا ينبغي عليك أن تعدّل أيٍ من هذه الأسطر، لكنك يجب أن تكون مدركًا لأهمية العثور على جميع مُدخلات السجل الدالة على وقوع خطأ استخدام غير مُصرّح به للتطبيق الذي تعمل على حمايته؛ فيما لو رغبت بتصميم مرشّح خاص بشكل يدوي.
في الجزء السفليّ من الملف يمكنك أن ترى المعامل ignoreregex فارغ حاليًا، والذي يمكن استخدامه لاستبعاد أنماط أكثر تحديدًا تطابق عادةً حالات فشل مصادقة لا ترغب لـ fail2ban بنفيها لاحتمالات مختلفة. لن نُعدّل شيئًا هنا.
احفظ الملف وأغلقه بعد الانتهاء من دراسته.
شرح ملف الإجراء
دعونا الآن نلقي نظرة على ملف الإجراء action file المسؤول عن إعداد جدار الحماية وفق صيغة تُسهّل التعديلات لحظر المُضيفين المُسيئين malicious hosts إضافةً إلى ضمهم أو حذفهم عند الضرورة.
وكما تذكرون يُدعى الإجراء الخاص باستدعاء خدمة SSH لدينا بـ iptables-multiport، لنفتح الآن الملف المرتبط بها:
sudo nano /etc/fail2ban/action.d/iptables-multiport.conf
بحذف التعليقات يبدو الملف مشابهًا لهذا:
[INCLUDES] before = iptables-blocktype.conf [Definition] actionstart = iptables -N fail2ban- iptables -A fail2ban- -j RETURN iptables -I -p -m multiport –dports -j fail2ban- actionstop = iptables -D -p -m multiport –dports -j fail2ban- actioncheck = iptables -n -L | grep -a ‘fail2ban-[ \t]’ actionban = iptables -I fail2ban- 1 -s -j actionunban = iptables -D fail2ban- -s -j [Init] name = default port = ssh protocol = tcp chain = INPUT
يبدأ الملف بتضمين محتوى ملف إجراء آخر يُدعى i iptables-blocktype.confوالذي يُعرّف ببساطة المُعامل blocktype المسؤول عن ضبط القيود التي سيتم فرضها على العميل المحظور.
بشكلٍ افتراضي يتم تعيين blocktype لرفض الحزم packets الواردة من قبل العميل المحظور وإعادتها مع رسالة تفيد بأنّ المنفذ المطلوب غير قابل للوصول حاليًا، وهذا ما سوف نستخدمه في قواعد الحظر تاليًا.
بعد ذلك تأتي تعريفات القواعد نفسها حيث معظم الإجراءات واضحة إلى حدٍ ما، فالإجراء actionstart يقوم بإعداد جدار الحماية iptables عند بدء تشغيل خدمة fail2ban، إذ يُنشئ سلسلة جديدة مُضيفًا إليها قاعدة للعودة إلى سلسلة الدعوة calling chain، ثم يدرج قاعدة في بداية سلسلة INPUT والتي تقوم بتمرير حركة البيانات المُطابقة للبروتوكول والمنفذ الصحيحين المتجهين إلى السلسلة الجديدة.
يتم ذلك باستخدام القيم التي قمنا بتمريرها مع الإجراء المُعرّف في ملف jail.local الخاص بنا. كما تؤخذ قيمة الخانة name من ترويسة المقطع المرتبط بكلّ خدمة، بينما تؤخذ قيم chain،protocol وport من سطر action نفسه من الملف.
ولعلكم تذكرون أن هذه أيضًا - بدورها- أضيفت إلى سطر الإجراء عبر إدخال مُعاملات أخرى مُحددة في أماكن أخرى من هذا الملف. إلى الآن فإن fail2ban قد مرّر وحوّل العديد من المُعاملات بين الأجزاء المختلفة من ملفات الضبط الخاصة به.
جميع المُعاملات التي تم تعيينها من قبل ملف آخر يُشار إليها عبر تضمين اسم المُعامل بقوسي زاوية:
عندما ننتقل إلى الأسفل نحو تعريف الإجراء actionstop نرى بأن أوامر جدار الحماية تُنفّذ ببساطة عكس أوامر الإجراء actionstart؛ حيث نُنهي صيغة جدار الحماية المُنشأة عندما نوقف خدمة fail2ban.
يتأكّد الإجراء actioncheck من إنشاء السلسة المناسبة قبل محاولة إضافة قواعد الحظر.
بعد ذلك نصل إلى قاعدة الحظر الفعلية actionban والتي تعمل عن طريق إضافة قاعدة جديدة إلى السلسلة المُنشأة، تطابق هذه القاعدة عنوان IP المصدر للعميل المُسيء (يُقرأ هذا المُعامل من قبل سجلات التصريح authorization logs عندما تُبلغ العتبة maxretry) ويتم تأسيس الحظر بتعريف المُعامل blocktype الموجود في المقطع [INCLUDE] في الجزء العلوي من الملف.
تزيل actionunban ببساطة القاعدة المُنشأة ويتم ذلك تلقائيًا بواسطة fail2ban بعد انقضاء وقت الحظر.
أخيرًا نصل إلى القسم [Init] والذي يقتصر دوره على تزويد بعض الافتراضات في حال استدعاء ملف الإجراء من دون تمرير جميع القيم اللازمة.
ترجمة -وبتصرف- للمقال How Fail2ban Works to Protect Services on a Linux Server لصاحبه Justin Ellingwood.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.