كيف تضبط "الطرق على المنافذ" على أوبنتو باستخدام IPTables


محمد أحمد العيل

قدمنا في الجزء الأول من هذا الدليل الخطة التي نعمل على إعدادها من أجل ضبط آلية للطرق على المنافذ تعتمد حصرا على جدار iptables الناري. نستكمل في هذا الجزء ما بدأناه بتنفذ الآلية المشروحة في الجزء السابق.

port-knocking.thumb.png.b25d4b1fc5df78c0

إعداد إطار عمل نظامي للجدار الناري

نبدأ بوضع إطار أساسي للاتصالات في الخادوم. ستتولى سلسلة INPUT التعامل مع جميع الاتصالات القادمة. سنزيل جميع قواعد الجدار الناري المطبقة حاليا من أجل بدء الإعداد من الصفر. لكن قبل ذلك يجب أن نتأكد من أن السياسات الافتراضية مضبوطة على ACCEPT للاستمرار في الاتصال الجاري:

sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -F

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

sudo iptables -N KNOCKING
sudo iptables -N GATE1
sudo iptables -N GATE2
sudo iptables -N GATE3
sudo iptables -N PASSED

نتوفر الآن على ثماني سلاسل. سنستخدمها كلَّها ما عدا سلسلتيْ OUTPUT وFORWARD اللتان لا تعنياننا هنا.

نبدأ بالتعامل مع الاتصالات التي لا تحتاج للطرق على المنافذ لفتحها، فنضيف قاعدة إلى سلسلة INPUT للسماح للاتصالات الجارية كافةً بالاستمرار:

sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

وأخرى لقبول جميع الاتصالات من الجهاز المحلي:

sudo iptables -A INPUT -i lo -j ACCEPT

إذا كانت لديك خدمات موجَّهة للعموم، مثل خادوم ويب، فأضف قاعدة على النحو التالي حتى يمكن الاتصال بها:

sudo iptables -A INPUT -p protocol --dport port -j ACCEPT

مثال لقاعدة تتيح الوصول إلى خادوم الويب:

sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT

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

sudo iptables -A INPUT -j KNOCKING

إعداد البوابة الأولى

سنُلحِق “البوابات” بعد اكتمال إعدادها بسلسلة KNOCKING لتمرير حركة البيانات عبر الاختبارات المشروحة في الجزء الأول من هذا الدليل. لكن قبل ذلك يجب وضع أساس كل اختبار على انفراد.

نبدأ بتعريف أول اختبار طرْق.

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

نضع علامة على العميل عند محاولة الاتصال بالمنفذ الصحيح:

sudo iptables -A GATE1 -p tcp --dport 1111 -m recent --name AUTH1 --set -j DROP

يؤدي السطر أعلاه مهام عدة؛ يضيف قاعدة جديدة إلى سلسلة GATE1. شروط تنفيذ القاعدة هي أن يكون البروتوكول المستخدَم هو tcp والمنفذ المطلوب هو1111، أي المنفذ اﻷول في سلسلة الطرق. عند تحقق الشروط نستدعي وِحدة recent (باستخدام خيار m-) ونضع علامة AUTH1 (باستخدام name AUTH1 --set--). ستُستعمَل هذه العلامة عند اختبار إصابة المنفذ الثاني. أخيرا، وبعد تعيين العلامة، نتجاهل الحزمة لكي لا يعرف العميل مالذي يحدث.

ثم نتجاهل جميع حزم البيانات الأخرى، لأن أي معلومة تُرسَل إلى هذه السلسلة تبحث فقط عن موافقة أول حزمة:

sudo iptables -A GATE1 -j DROP

أنجزنا الآن ما يتعلق بالمنفذ الأول من متتالية الطرْق: إما أن توافق الحزمة المنفذ المطلوب أو تُتَجاهَل. إذا وافقت المنفذ توضع عليها علامة AUTH1.

إعداد البوابة الثانية

تُضبط البوابة الثانية بطريقة مشابهة إلا أنها أكثر تعقيدا.

أول ما يجب الانتباه إليه هو أن قرار توجيه محاولات الاتصال إلى هذه السلسلة سيكون ضمن السلسلة الأم KNOCKING. لن تحتاج سلسلة GATE2 إلى التأكد من مطابقة محاولة الاتصال للبوابة الأولى، لأن هذا الاختبار جرى سلفا.

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

نستخدم وحدة recent مرة أخرى لحذف الاسم (العلامة):

sudo iptables -A GATE2 -m recent --name AUTH1 --remove

لا تتخذ القاعدة أعلاه أي قرارات أو إعادة توجيه؛ كل ما تفعله هو حذف العلامة الحالية (وهي تلك التي سمحت بتوجيه الاتصال إلى هذه السلسلة) وتوجيه البيانات إلى القاعدة الموالية.

يصبح العنوان - بعد تجاوز القاعدة الأولى من السلسلة - خاليا من أي علامات. نتحقق من المنفذ الذي يطلبه العنوان ومن مطابقته للمنفذ الثاني في متتالية الطرْق (2222):

sudo iptables -A GATE2 -p tcp --dport 2222 -m recent --name AUTH2 --set -j DROP

نفس ما فعلناه مع البوابة الأولى. نضع علامة AUTH2 للإشارة إلى أن عنوان الطلب تجاوز الاختبار الثاني إذا كان العميل يحاول الاتصال عبر المنفذ المطلوب، ثم نتجاهل الحزمة لكي لا يعرف العميل مالذي نفعله.

قد تبدو القاعدة التالية غريبة لأول وهلة:

sudo iptables -A GATE2 -j GATE1

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

لو كانت لدينا قاعدة drop all هنا وكانت الحزمة المرسلة في هذه الأثناء توافق المنفذ الأول في سلسلة الطرْق، فلن تسجَّل على أنها بداية لمتتالية الطرق. نفرض على سبيل المثال أن العميل أرسل - عن طريق الخطأ - محاولتي اتصال إلى المنفذ الأول. في هذه الحالة لن يعُدّ الجدار الناري محاولة الاتصال الثانية صحيحة لأنه سيرى المتتالية كما يلي:

  • محاولة اتصال عبر المنفذ الأول. سيحسب الجدار الناري أن الاختبار الأول تُجووِز بنجاح.
  • محاولة الاتصال عبر المنفذ الأول. فشل في الاختبار الثاني. يُعاد تعيين المتتالية.
  • محاولة الاتصال عبر المنفذ الثاني. فشل في الاختبار الأول (يطبَّق الاختبار الأول لأن المتتالية أعيد تعيينها في الخطوة السابقة). يُعاد تعيين المتتالية.
  • محاولة الاتصال عبر المنفذ الثالث. فشل في الاختبار الأول (يُطبق الاختبار الأول لأن المتتالية أعيد تعيينها في الخطوة السابقة). يُعاد تعيين المتتالية.

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

لتجنب الوقوع في هذه الحالة لن نتجاهل الحزمة بل سنوجّهها - بدلا من ذلك - إلى سلسلة GATE1 التي أعددناها سابقا. نرسل جميع حزم البيانات التي لم تُصِب المنفذ الثاني إلى البوابة الأولى من جديد:

sudo iptables -A GATE2 -j GATE1

نكون هنا أمام خيارين: إما أن يكون الطلب موجَّها إلى المنفذ الأول، هنا نبدأ من جديد في المتتالية؛ وإلا فإن الجدار الناري سيتجاهل الطلب حسب العادة. أي أننا تجنبنا الوقوع في الحالة المعروضة آنفا.

إعداد البوابة الثالثة

ننفذ البوابة الثالثة بنفس طريقة تنفيذ البوابة الثانية تماما.

نمسح أولا جميع العلامات التي وُضعت على العنوان مثل ما فعلنا في إعداد البوابة الثانية ولنفس الأسباب:

sudo iptables -A GATE3 -m recent --name AUTH2 --remove

ثم نختبر هل أصابت محاولة الاتصال المنفذ الثالث في متتالية الطرق، فإن فعلت نضع علامة AUTH3 التي تشير إلى أن العميل نجح في طرق المنافذ المطلوبة حسب المرجو؛ ثم نتجاهل - مثل ما هي العادة - الحزمة:

sudo iptables -A GATE3 -p tcp --dport 3333 -m recent --name AUTH3 --set -j DROP

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

sudo iptables -A GATE3 -j GATE1

بالوصول إلى هذه النقطة يكون العملاء الذي نجحوا في طرق المنافذ المطلوبة حسب الترتيب المفروض قد حصلوا على علامة AUTH3 التي تمكننا من فتح خدمة SSH لهم ضمن سلسلة PASSED.

إعداد سلسلة PASSED

تُستخدَم هذه السلسلة لفتح منفذ SSH لمدة ثلاثين ثانية للعميل الذي نجح في طرق المتتالية الصحيحة.

لن يُفتَح منفذ SSH إلا إذا كانت محاولة الاتصال الموالية من العميل تطلب السماح لها بعبوره. تفرض هذه القاعدة على من يحاول عشوائيا طرق المنافذ تجربة الاتصال بSSH بعد كل محاولة، الأمر الذي يصعِّب من معرفة متتالية الطرق.

نبدأ - حسب العادة - بإعادة تعيين العلامات:

sudo iptables -A PASSED -m recent --name AUTH3 --remove

نقبل الاتصال عبر SSH من المستخدمين الذين وصلوا إلى هذه السلسلة:

sudo iptables -A PASSED -p tcp --dport 22 -j ACCEPT

بالنسبة للمستخدمين الذي لم يحاولوا الاتصال عبر SSH فإننا نعيدهم إلى البوابة الأولى:

sudo iptables -A PASSED -j GATE1

أكملنا الآن إعداد جميع السلاسل المتفرعة عن سلسلة KNOCKING. بقي إعداد السلسلة العامة التي ستمرر حركة البيانات إلى السلاسل الفرعية.

إعداد سلسلة KNOCKING

يمكننا الآن بعد إعداد السلاسل الفرعية منفردةً إلحاقها بالسلسلة العامة KNOCKING وبالتالي تنفيذ خطة عملنا.

نبدأ أولا بتوجيه اتصالات العملاء الذين نجحوا في اختبارات الطرْق مباشرة إلى سلسلة PASSED. تمكننا إضافة خيارات هنا. سنقيد الفترة الزمنية التي يمكن للعميل الاتصال فيها بخدمة SSH بعد تجاوزه لاختبارات الطرق، ولتكن ثلاثين ثانية. بعد هذه المهلة لن يكون بمقدوره الاتصال ويجب عليه إرسال متتالية الطرق مرة أخرى.

sudo iptables -A KNOCKING -m recent --rcheck --seconds 30 --name AUTH3 -j PASSED

ثم نختبر العلامات الأخرى بدءا بالأكثر تقييدا. تمكننا إضافة عشر ثوان لتحديد مهلة لانتهاء صلاحية الطَّرْقات؛ يعني هذا أنه يتوجب على العملاء ألايفصلوا بين كل طرْقتين بأكثر من عشر ثوان.

sudo iptables -A KNOCKING -m recent --rcheck --seconds 10 --name AUTH2 -j GATE3
sudo iptables -A KNOCKING -m recent --rcheck --seconds 10 --name AUTH1 -j GATE2

نعيد توجيه جميع محاولات الاتصال التي لم توافق أيا من القواعد السابقة إلى البوابة الأولى:

sudo iptables -A KNOCKING -j GATE1

بهذا تأخذ جميع سلاسل الجدار الناري مكانها. تُلحَق سلسلة KNOCKING كاملة مع السلاسل التابعة لها بسلسلة INPUT الاعتيادية.

أعددنا لآن آلية الطرق. حان الوقت لاختبارها.

اختبار الطرق على المنافذ

توجد الكثير من الأدوات التي يمكن استخدامها لإنشاء حزم بيانات تستخدم بروتوكول TCP المطلوبة في إعدادات الطرْق على المنافذ. سنستخدم أداة nmap نظرا لوجودها افتراضيا على أغلب توزيعات لينكس.

يستخدم nmap افتراضيا حزم بيانات TCP. لذا يجب أن نطلب منه تجاهل استكشاف المستضيف الموجود في سلوكه الابتدائي لكي لا يتداخل مع الطرْقات. إضافة لذلك نريد أن تنتهي مهلة محاولة الاتصال بعد ثانية واحدة فقط لنتابع مع الطرقة الموالية.

ستبدو كل طرْقة، من هذا المنطلق، على النحو التالي. في المثال أول منفذ نريد طرْقه:

nmap -Pn --host_timeout 201 --max-retries 0 -p 1111 your_server

أي أن متتالية الطرق ستصبح على النحو التالي:

nmap -Pn --host_timeout 201 --max-retries 0 -p 1111 your_server
nmap -Pn --host_timeout 201 --max-retries 0 -p 2222 your_server
nmap -Pn --host_timeout 201 --max-retries 0 -p 3333 your_server

ستكون لدينا بعدها ثلاثون ثانية للاتصال بخدمة SSH.

يمكننا الاستفادة من أساسيات في برمجة Bash لجعل الأمور آليةً أكثر. سنستخدم حلقة for لتنفيذ الأوامر السابقة ضمن حلقة تكرارية ثم تشغيل عميل SSH للاتصال بالخادوم:

for x in 1111 2222 3333; do nmap -Pn --host_timeout 201 --max-retries 0 -p $x your_server && sleep 1; done && ssh user@your_server

ما نفعله هنا هو الطرْق على المنفذ الأول، انتظار ثانية واحدة، الطرْق على الثاني، وهكذا إلى أن تكتمل المتتالية. ثم نحاول بعدها الاتصال بخدمة SSH على الخادوم.

ننشئ ملفا للسكربت لجعل الأمر أكثر أناقة وأيسر للاستخدام. نسمي الملف knock_client:

nano knock_client

ونضع فيه المحتوى التالي:

#!/bin/bah

ports="1111# 2222 3333"
host="your_server"

for x in $ports
do
nmap -Pn --host_timeout 201 --max-retries 0 -p $x $host
sleep 1
done
ssh user@${host}

احفظ الملف (CTRL + O) ثم أغلقه (CTRL + X).

نجعل الملف قابلا للتنفيذ:

chmod 755 knock_client

نحاول الاتصال بالخادوم بتنفيذ الأمر:

./knock_client

يمكن الآن، إذا جرى كل شيء على ما يرام، الاتصال بالخادوم عن طريق SSH.

بقيت خطوة أخيرة بعد التحقق من عمل الخطة التي نفذناها حسب المُراد. نجعل قواعد الجدار الناري دائمة (لا يُعاد تعيينها بعد إعادة تشغيل الخادوم) بتنزيل وتثبيت حزمة iptables-persistent على الخادوم:

sudo apt-get install iptables-persistent

وتشغيل خدمة iptables-persistent:

sudo service iptables-persistent start

خاتمة

يكون لديك باكتمال هذا الدليل نظام عملي للطرق على المنافذ يعتمد فقط على الوظائف الموجودة في جدار iptables الناري.

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

ميزة أخرى لهذا الإعداد في مقابل خدمة منفصلة للطرق على المنافذ هي أنه لا مجال أن تفشل خدمة تنفيذ الطرق في تغيير قواعد الجدار الناري وتدع المنفذ مفتوحا.

ترجمة - بتصرف - لمقال How To Configure Port Knocking Using Only IPTables on an Ubuntu VPS.

حقوق الصورة البارزة: Shield vector designed by Freepik.





تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن