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:… (নির্দিষ্ট ঠিকানা)যে কেউ যে ওই ঠিকানায় পৌঁছাতে পারে

অর্থাৎ নতুন সার্ভার বাইরে শুধু একটি জিনিস খোলে: পোর্ট 22-এ SSH, IPv4 ও IPv6-এ। 127.0.0.53-এর DNS রিজলভার ব্যক্তিগত।

ইন্টারনেট যা দেখতে পারে শুধু তা দেখাতে loopback ঠিকানাগুলো বাদ দিন:

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

প্রতিটি ইনস্টলের পরে এটি চালান। আমরা nginx, Docker আর একটি ছোট Python অ্যাপ ইনস্টল করেছিলাম, তালিকা 2 লাইন থেকে 10 লাইনে দাঁড়াল, যার মধ্যে ছিল 0.0.0.0:8081-এ docker-proxy এবং একটি এলোমেলো localhost পোর্টে containerd-এর সকেট।

2. কোন প্রসেস পোর্ট দখল করেছে

পোর্ট ব্যস্ত থাকলে এবং কে নিয়েছে জানতে চাইলে:

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

পড়তে সবচেয়ে সহজ lsof। nginx-এর জন্য এটি root হিসেবে একটি মাস্টার প্রসেস আর www-data হিসেবে একটি worker দেখাল, দুটোই *:80-এ, IPv4 ও IPv6-এর জন্য। fuser শুধু PID ছাপে, স্ক্রিপ্টে কাজে লাগে। পোর্ট খালি করতে হলে PID মারার বদলে সার্ভিস থামান, নইলে systemd আবার চালু করবে: sudo systemctl stop nginx।

3. ইন্টারনেট কী দেখে

ss সার্ভারের দৃষ্টিভঙ্গি দেখায়। ইন্টারনেটের দৃষ্টিভঙ্গি আলাদা হতে পারে, কারণ মাঝে ফায়ারওয়াল আছে বা সার্ভিসটি 127.0.0.1-এ বাঁধা। আসল ছবি দেখতে সার্ভারটি অন্য মেশিন থেকে স্ক্যান করুন, আপনার ল্যাপটপ বা দ্বিতীয় সার্ভার থেকে। টুলটি nmap (apt install nmap, অথবা Windows ও macOS-এ nmap.org-এর ইনস্টলার)।

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 সার্ভার-ip 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। ডেটাবেসের জন্য এটাই সঠিক ডিফল্ট: Ubuntu-তে Redis, MySQL ও PostgreSQL শুরু থেকেই 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 সৎভাবে এটিকে 0.0.0.0:8081-এ docker-proxy হিসেবে দেখায়।

সমাধান হল শুধু 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। পাবলিক দিকের জন্য HTTPS সহ nginx-কে reverse proxy হিসেবে সামনে রাখুন, যাতে সার্ভারে শুধু পোর্ট 22, 80 ও 443 খোলা থাকে।

প্রতিটি পরিবর্তনের পরে চেকলিস্ট

  1. sudo ss -tulpn: 0.0.0.0 বা [::] থাকা প্রতিটি লাইন কি এমন কিছু যা আপনি খুলতে চেয়েছিলেন?
  2. ল্যাপটপ থেকে nmap সার্ভার-ip: খোলা পোর্ট কি মিলছে?
  3. পাবলিক ঠিকানায় ডেটাবেস, ক্যাশ বা অ্যাডমিন প্যানেল: আজই 127.0.0.1-এ বা ফায়ারওয়ালের পেছনে সরান।
  4. Docker-এর প্রতিটি ports: এন্ট্রি: পাবলিক ওয়েব পোর্ট না হলে কি 127.0.0.1: দিয়ে শুরু হয়?
  5. SSH সবার জন্য খোলা: fail2ban বা শুধু কী দিয়ে লগইন যোগ করুন।

Windows Server-এ একই পরীক্ষা Get-NetTCPConnection -State Listen, আর নিয়মগুলো থাকে Windows Firewall-এ। $3-এর Nano থেকে শুরু করে প্রতিটি Linux প্ল্যানের নিজস্ব IPv4 ঠিকানাসহ একটি সংস্করণ আছে, আর সেখানে আপনি ss-এ যা দেখেন, গোটা বিশ্বও তাই দেখে, শুধু আপনার ফায়ারওয়াল যা আটকায় তা বাদে।

FAQ

নতুন VPS-এ কোন পোর্টগুলো খোলা থাকে?

আমাদের Ubuntu 24.04 ইমেজে মাত্র একটি: পোর্ট 22-এ SSH। এ ছাড়া শুধু 127.0.0.53 ও 127.0.0.54-এ লোকাল DNS রিজলভার শোনে, যেখানে ইন্টারনেট পৌঁছাতে পারে না। অন্য মেশিন থেকে সব 65,535 TCP পোর্ট স্ক্যান করে ঠিক একটি খোলা পোর্ট পাওয়া গেছে।

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 সার্ভার-ip 443 চালান, অথবা nmap ইনস্টল করে সবচেয়ে প্রচলিত হাজারটি পোর্টের জন্য nmap সার্ভার-ip চালান। NAT প্ল্যানে ইন্টারনেট থেকে শুধু আপনার ফরোয়ার্ড করা SSH পোর্ট উত্তর দেয়; বাকি সব ইচ্ছাকৃতভাবে নাগালের বাইরে।

মন্তব্য

এখনো কোনো মন্তব্য নেই। প্রথম হোন।

একটি মন্তব্য দিন

মন্তব্য প্রকাশের আগে মডারেট করা হয়।