پورتی که باز مانده و فراموش شده، راه کلاسیک ورود به سرور است: پایگاه دادهای روی آدرس عمومی، داشبورد دیباگ، کانتینری که پورتی را منتشر کرده که هیچکس نمیخواست. اگر دو دستور و یک تله را بشناسید، بررسی یک دقیقه طول میکشد. همهٔ مراحل زیر را روی یک سرور تازهٔ 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. resolver DNS روی 127.0.0.53 خصوصی است.
برای دیدن فقط آنچه اینترنت میتواند ببیند، آدرسهای loopback را فیلتر کنید:
sudo ss -tlnp | awk 'NR>1 && $4 !~ /^(127\.|\[::1\])/ {print $4, $6}'
این را بعد از هر نصب اجرا کنید. ما nginx، Docker و یک برنامهٔ کوچک Python نصب کردیم و فهرست از 2 خط به 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 و یک worker با www-data نشان داد، هر دو روی *:80 برای IPv4 و IPv6. fuser فقط PIDها را چاپ میکند که در اسکریپتها به کار میآید. اگر لازم است پورت را آزاد کنید، بهجای کشتن PID سرویس را متوقف کنید، وگرنه 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 ثانیه طول کشید و همان یک پورت را پیدا کرد. پورتهای بسته فوراً با reset جواب میدهند، برای همین اسکنشان سریع است.
سه وضعیت مهم است:
- open: برنامهای اتصال را پذیرفته. این سطح حملهٔ شماست.
- closed: سرور جواب داده که آنجا چیزی گوش نمیدهد. امن است، اما تأیید میکند سرور وجود دارد و چه چیزی را اجرا نمیکند.
- filtered: هیچ جوابی نیست. فایروال بسته را دور ریخته. اسکنر نمیتواند بداند پشتش سرویسی هست یا نه.
برای یک پورت بدون نصب چیزی، nc -zv آیپی-سرور 443 پاسخ succeeded یا refused میدهد و روی پورت فیلترشده تا پایان مهلت منتظر میماند. برای UDP به nmap گزینهٔ -sU را اضافه کنید و منتظر کندی باشید؛ روی سرور ما سه پورت رایج 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 روی Ubuntu از همان ابتدا روی localhost گوش میدهند و راهنماهای ما برای 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 پورت حالا بهجای 8.9 ثانیه 110 ثانیه طول کشید. زمان بیشتر برای هر پورت برای اسکنر، اطلاعات کمتر دربارهٔ سرور شما. راهنمای 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 زیر ports: بنویسید "127.0.0.1:8081:80". پس از تغییر، ss نشانی 127.0.0.1:8081 را نشان داد، قانون Docker بخش -d 127.0.0.1/32 را گرفت و اسکن از بیرون 8081/tcp filtered گزارش کرد. برای سمت عمومی nginx را بهعنوان reverse proxy با HTTPS جلویش بگذارید تا تنها پورتهای باز سرور 22، 80 و 443 باشند.
چکلیست بعد از هر تغییر
sudo ss -tulpn: آیا هر خط با0.0.0.0یا[::]چیزی است که میخواستید باز باشد؟nmap آیپی-سروراز لپتاپ: آیا پورتهای باز میخوانند؟- پایگاه داده، کش یا پنل مدیریت روی آدرس عمومی: همین امروز به
127.0.0.1یا پشت فایروال منتقلش کنید. - هر مدخل
ports:در Docker: اگر پورت وب عمومی نیست، با127.0.0.1:شروع میشود؟ - SSH برای همه باز است: fail2ban یا ورود فقط با کلید را اضافه کنید.
در Windows Server همین بررسی با Get-NetTCPConnection -State Listen انجام میشود و قوانین در فایروال Windows قرار دارند. هر پلن لینوکسی، از Nano با $3 به بالا، نسخهای با آدرس IPv4 اختصاصی دارد و آنجا هرچه در ss میبینید، کل دنیا هم میبیند، جز آنچه فایروالتان جلویش را میگیرد.
نظرات
هنوز نظری نیست. اولین نفر باشید.