EQVPS
لوحة التحكمابدأ الآن

كيف تفحص المنافذ المفتوحة على VPS: ما الذي يستمع، وما الذي يراه الإنترنت، ومفاجأة Docker

اطّلع على كل منفذ يستمع عليه خادمك، واعثر على العملية التي خلفه، وافحص الخادم من الخارج كما يفعل المهاجم، وأغلق ما لا تحتاجه. ومعه منفذ Docker الذي يبقى مفتوحًا حتى مع تشغيل الجدار الناري. كل رقم قيس على خادم Ubuntu 24.04 جديد.

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

1. ما الذي يستمع

الأمر هو ss. تعني الأحرف: TCP وUDP والمقابس المستمعة وأرقام المنافذ واسم العملية:

sudo ss -tulpn

على خادم جديد يطبع ستة أسطر:

Netid State  Local Address:Port  Process
udp   UNCONN    127.0.0.54:53    systemd-resolve
udp   UNCONN 127.0.0.53%lo:53    systemd-resolve
tcp   LISTEN    127.0.0.54:53    systemd-resolve
tcp   LISTEN 127.0.0.53%lo:53    systemd-resolve
tcp   LISTEN       0.0.0.0:22    sshd
tcp   LISTEN          [::]:22    sshd

العمود المهم هو Local Address. يخبرك من يستطيع الاتصال:

العنوانمن يصل إليه
127.0.0.1:… أو 127.0.0.53البرامج على هذا الخادم فقط
0.0.0.0:…أي أحد عبر IPv4، ما لم يحجبه الجدار الناري
[::]:…أي أحد عبر IPv6 (وعادةً IPv4 أيضًا)
10.0.0.5:… (عنوان محدد)كل من يستطيع الوصول إلى ذلك العنوان

إذن لا يكشف الخادم الجديد للخارج إلا شيئًا واحدًا: SSH على المنفذ 22 عبر IPv4 وIPv6. أما محلّل DNS على 127.0.0.53 فخاص.

لعرض ما قد يراه الإنترنت فقط، استبعد عناوين loopback:

sudo ss -tlnp | awk 'NR>1 && $4 !~ /^(127\.|\[::1\])/ {print $4, $6}'

شغّل هذا بعد كل تثبيت. ثبّتنا nginx وDocker وتطبيق Python صغيرًا، فكبرت القائمة من سطرين إلى 10 أسطر، منها docker-proxy على 0.0.0.0:8081 ومقبس containerd على منفذ localhost عشوائي.

2. أي عملية تشغل المنفذ

عندما يكون المنفذ مشغولًا وتريد معرفة من يشغله:

sudo lsof -i :80 -P -n
sudo fuser 80/tcp
sudo ss -tlnp 'sport = :80'

الأسهل قراءة هو lsof. أظهر لـ nginx عملية رئيسية باسم root وعاملًا باسم www-data، كلاهما على *:80 لكل من IPv4 وIPv6. أما fuser فيطبع أرقام العمليات فقط، وهو مفيد في السكربتات. إذا احتجت إلى تحرير المنفذ فأوقف الخدمة بدل قتل العملية، وإلا أعاد systemd تشغيلها: sudo systemctl stop nginx.

3. ما الذي يراه الإنترنت

يعرض ss منظور الخادم. وقد يختلف منظور الإنترنت، لأن بينهما جدارًا ناريًا أو لأن الخدمة مربوطة بـ 127.0.0.1. لرؤية الصورة الحقيقية افحص الخادم من جهاز آخر، كحاسوبك المحمول أو خادم ثانٍ. الأداة هي nmap (apt install nmap، أو المثبّت من nmap.org على Windows وmacOS).

nmap your-server-ip
nmap -p- your-server-ip
nmap -p 22,80,443,3306 your-server-ip

الصيغة الأولى تفحص أكثر 1,000 منفذ شيوعًا، والثانية كل المنافذ الـ 65,535، والثالثة قائمة محددة. على خادمنا الجديد قبل أي جدار ناري:

Not shown: 999 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
Nmap done: 1 IP address (1 host up) scanned in 6.83 seconds

استغرق الفحص الكامل للمنافذ الـ 65,535 مدة 8.9 ثانية ووجد المنفذ الوحيد نفسه. المنافذ المغلقة ترد فورًا بإعادة ضبط، ولهذا يكون فحصها سريعًا.

ثلاث حالات مهمة:

  • open: قبل برنامج ما الاتصال. هذا هو سطح الهجوم لديك.
  • closed: ردّ الخادم بأن لا شيء يستمع هناك. آمن، لكنه يؤكد أن الخادم موجود وما الذي لا يشغّله.
  • filtered: لا رد. أسقط جدار ناري الحزمة. لا يستطيع الماسح معرفة إن كانت خلفه خدمة.

لمنفذ واحد دون تثبيت أي شيء، يُبلغ nc -zv عنوان-الخادم 443 بـ succeeded أو refused، ويبقى معلّقًا حتى انتهاء المهلة على المنفذ المُرشَّح. أما UDP فأضف -sU إلى nmap وتوقّع البطء؛ على خادمنا كانت منافذ UDP الشائعة الثلاثة 53 و123 و161 كلها closed.

ملاحظة عن خطط NAT: لا يصل من الإنترنت إلا منفذ SSH الذي حوّلناه إليك. فحص العنوان المشترك يُظهر حافة شبكتنا لا خادمك، وبقية المنافذ غير قابلة للوصول أيًّا كان ما يستمع عليها. في خطة بعنوان IPv4 خاص تدير أنت كل منفذ مفتوح.

4. أغلق ما لا تحتاجه

ثلاث طرق، من الأفضل إلى الأوسع.

اربط الخدمة بـ localhost. إذا كانت البرامج على الخادم وحدها تستخدم خدمة ما، فاجعلها تستمع على 127.0.0.1. شغّلنا تطبيق ويب صغيرًا بـ --bind 127.0.0.1 8080: أظهره ss على 127.0.0.1:8080، وأبلغ nmap من الخارج عن 8080/tcp closed. هذا هو الإعداد الافتراضي الصحيح لقواعد البيانات: Redis وMySQL وPostgreSQL تستمع على localhost مباشرة بعد التثبيت على Ubuntu، ودليلانا لـ Redis وMySQL يُبقيانها كذلك.

أوقف الخدمة. يزيل sudo systemctl disable --now الاسم المستمع نهائيًا. تحقق بـ ss من اختفائه.

شغّل الجدار الناري. اسمح بـ SSH أولًا، ثم بما تقدّمه، ثم فعّله:

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw enable
sudo ufw status verbose

تغيّر الفحص من الخارج تمامًا:

Not shown: 997 filtered tcp ports (no-response)
PORT     STATE SERVICE
22/tcp   open  ssh
80/tcp   open  http
8081/tcp open  blackice-icecap
Nmap done: 1 IP address (1 host up) scanned in 10.18 seconds

انتقل كل منفذ غير مسموح به من closed إلى filtered، وأصبح الفحص الكامل للمنافذ الـ 65,535 يستغرق 110 ثوانٍ بدل 8.9. وقت أطول لكل منفذ لدى الماسح، ومعلومات أقل عن خادمك. يشرح دليل UFW لدينا تحديد المعدل والسماح لعنوان IP واحد وIPv6.

لكن انظر إلى السطر الثالث.

5. مفاجأة Docker

بقي المنفذ 8081 مفتوحًا مع تشغيل الجدار الناري ودون أي قاعدة تسمح به. هذا المنفذ يخص حاوية شغّلناها بـ docker run -p 8081:80 nginx:alpine. يضيف Docker قواعده الخاصة إلى جدار النواة الناري، وتُقيَّم هذه القواعد قبل قواعد ufw. القاعدة التي كتبها على خادمنا:

-A DOCKER ! -i docker0 -p tcp --dport 8081 -j DNAT --to-destination 172.17.0.2:80

كل حزمة متجهة إلى المنفذ 8081 تُحوَّل إلى الحاوية قبل أن تتاح لـ ufw كلمة. تفعل ذلك كل حاوية فيها -p أو مدخل ports:، ويعرضها ss بأمانة على أنها docker-proxy على 0.0.0.0:8081.

الحل هو النشر على localhost فقط:

docker rm -f web
docker run -d --name web -p 127.0.0.1:8081:80 nginx:alpine

في Compose اكتب "127.0.0.1:8081:80" تحت ports:. بعد التغيير أظهر ss العنوان 127.0.0.1:8081، واكتسبت قاعدة Docker الجزء -d 127.0.0.1/32، وأبلغ الفحص من الخارج عن 8081/tcp filtered. ضع nginx كوكيل عكسي في الأمام للجانب العام مع HTTPS، كي تكون المنافذ المفتوحة الوحيدة على الخادم هي 22 و80 و443.

قائمة تحقق بعد كل تغيير

  1. sudo ss -tulpn: هل كل سطر فيه 0.0.0.0 أو [::] شيء أردت كشفه؟
  2. nmap عنوان-الخادم من حاسوبك المحمول: هل تتطابق المنافذ المفتوحة؟
  3. قاعدة بيانات أو ذاكرة تخزين مؤقت أو لوحة إدارة على عنوان عام: انقلها اليوم إلى 127.0.0.1 أو خلف الجدار الناري.
  4. كل مدخل ports: في Docker: هل يبدأ بـ 127.0.0.1: إن لم يكن منفذ الويب العام؟
  5. SSH مفتوح للجميع: أضف fail2ban أو تسجيل الدخول بالمفتاح فقط.

على Windows Server يكون الفحص نفسه بالأمر Get-NetTCPConnection -State Listen، وتوجد القواعد في جدار Windows الناري. لكل خطة Linux، بدءًا من Nano بسعر $3، نسخة بعنوان IPv4 خاص، وهناك يرى العالم كله ما تراه في ss، باستثناء ما يحجبه جدارك الناري.

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

ما المنافذ المفتوحة على VPS جديد؟

على صورة Ubuntu 24.04 لدينا منفذ واحد: SSH على المنفذ 22. لا يستمع غيره إلا محلّل DNS المحلي على 127.0.0.53 و127.0.0.54، ولا يصل إليه الإنترنت. فحص جميع منافذ TCP البالغة 65,535 من جهاز آخر وجد منفذًا مفتوحًا واحدًا بالضبط.

ما الفرق بين المنفذ closed والمنفذ filtered؟

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

لماذا يُظهر ss منفذًا يقول nmap إنه closed؟

الخدمة تستمع على 127.0.0.1 فقط، أي عنوان loopback. تستطيع البرامج على الخادم نفسه الاتصال بها، ولا أحد من الخارج. في ss انظر إلى عمود Local Address: العنوان 127.0.0.1:8080 خاص، أما 0.0.0.0:8080 أو [::]:8080 فيمكن الوصول إليه من الإنترنت إذا سمح الجدار الناري.

شغّلت ufw، فلماذا ما زال منفذ Docker مفتوحًا؟

يكتب Docker قواعد جدار ناري خاصة به تُطبَّق قبل قواعد ufw. حاوية شُغّلت بـ -p 8081:80 كانت متاحة من الخارج على خادمنا مع تفعيل ufw ودون أي قاعدة للمنفذ 8081. انشر المنفذ على localhost بدلًا من ذلك: -p 127.0.0.1:8081:80، وضع nginx أو Caddy أمامها للجانب العام.

كيف أفحص منفذًا من حاسوبي؟

شغّل nc -zv عنوان-الخادم 443 لمنفذ واحد، أو ثبّت nmap وشغّل nmap عنوان-الخادم لأكثر ألف منفذ شيوعًا. في خطة NAT لا يرد من الإنترنت إلا منفذ SSH المُحوَّل إليك؛ وكل ما عداه غير قابل للوصول عن قصد.

التعليقات

لا تعليقات بعد. كن الأول.

اترك تعليقًا

تُراجَع التعليقات قبل ظهورها.