খোলা পোর্টের তালিকা হলো আপনার সার্ভারে পৌঁছানোর পথের তালিকা। বাকি সব — ফায়ারওয়াল, WAF, অনুপ্রবেশ শনাক্তকরণ — তার উপরেই গড়ে ওঠে। সেজন্যই যেকোনো নিরীক্ষায় «এখানে কী শুনছে» সবার আগে আসে, আর সেজন্যই এটিই সেই যাচাই যা সবচেয়ে বেশিবার অপ্রীতিকর উত্তর দেয়: যা পাওয়া যায় তার অর্ধেক আপনি নয়, কোনো প্যাকেজের ইনস্টলার খুলেছে।
ফলাফল পড়া
sudo ss -tulpn
পতাকাগুলো: t মানে TCP, u মানে UDP, l মানে কেবল যারা শুনছে, p মানে প্রক্রিয়া, n মানে সংখ্যাকে সংখ্যাই থাকতে দাও। sudo ছাড়া প্রক্রিয়ার কলাম ফাঁকা থাকে আর পুরো অনুশীলনটাই অর্থহীন হয়ে যায়।
গুরুত্বপূর্ণ হলো Local Address:Port কলাম, আর সেখানকার পার্থক্য মৌলিক:
127.0.0.1:3306— সেবাটি কেবল যন্ত্রটি থেকেই নাগালে। এটা ভালো;0.0.0.0:3306— প্রতিটি IPv4 ঠিকানা থেকে, অর্থাৎ ইন্টারনেট থেকে। এটিই যাচাই করার জিনিস;[::]:3306— IPv6-এর জন্য একই কথা। আলাদা লাইন, আর নিয়মিত উপেক্ষিত;203.0.113.25:443— নির্দিষ্ট একটা ঠিকানায়, সাধারণত ইচ্ছাকৃত।
তারপর 0.0.0.0 বা [::]-সহ প্রতিটি লাইনের জন্য একটাই প্রশ্ন করুন: অপরিচিত কারও কি এখানে পৌঁছাতে পারা উচিত। 80 ও 443-এর জন্য উত্তর হ্যাঁ। প্রায় বাকি সবের জন্য না।
চেনা আবিষ্কার
Redis, পোর্ট 6379। সেখানকার সবচেয়ে বিপজ্জনক লাইন। ডিফল্টে Redis-এর পাসওয়ার্ড লাগে না, আর তার কমান্ড ডিস্কে ফাইল লিখতে দেয় — অর্থাৎ authorized_keys-এ পরের কি। Redis-এর প্রকাশ্য ঠিকানায় আসা আর ব্যবহৃত হওয়ার মাঝে ঘণ্টা কাটে, কখনও তারও কম। কনফিগে bind 127.0.0.1 ও protected-mode yes যাচাই করুন।
Memcached, 11211/UDP। ভেতরে মূল্যবান কিছু না থাকলেও আপনার সার্ভার অন্যের আক্রমণের বিবর্ধক হয়ে ওঠে — আর অভিযোগ আসবে আপনার প্রদানকারীর কাছ থেকে।
MySQL ও PostgreSQL, 3306 ও 5432। পাসওয়ার্ড আছে, কিন্তু তার উপর অনুমান অবিরত চলে, আর ডেটাবেসের সংস্করণ কাঙ্ক্ষিতের চেয়ে কম হালনাগাদ হয়। তাদের প্রায় কখনও বাইরের দিকে থাকার দরকার হয় না: অ্যাপ্লিকেশন একই যন্ত্রে থাকে, আর নিজের কাজের জন্য SSH টানেলই যথেষ্ট।
Elasticsearch 9200, MongoDB 27017। ঐতিহাসিকভাবে ডিফল্টে প্রমাণীকরণ ছাড়াই। এদের প্রকাশ্য দৃষ্টান্ত তথ্য ফাঁসের খবরের স্থায়ী উৎস।
Docker API, 2375। খোলা Docker নিয়ন্ত্রণ পোর্ট মানে হোস্টে কোনো পাসওয়ার্ড ছাড়াই root। এটি সাধারণত Docker-এ দূরবর্তী প্রবেশাধিকারের পরীক্ষানিরীক্ষার পরে দেখা দেয়।
কন্ট্রোল প্যানেল ও phpMyAdmin নিজেদের পোর্টে: 8080, 8083, 10000। এমন নয় যে এগুলো কখনও খোলাই যাবে না, কিন্তু চেষ্টার বড় অংশ এগুলোই কুড়োয়।
ফায়ারওয়ালে নয়, সেবাতেই ঠিক করুন
প্রতিটি আবিষ্কার UFW-র নিয়ম দিয়ে বন্ধ করার ইচ্ছা বোধগম্য, কিন্তু সেটা দ্বিতীয় সারি, প্রথম নয়। নিয়ম ভুল করে মুছে যেতে পারে, ডিবাগ করার সময় ফায়ারওয়াল সাময়িকভাবে বন্ধ করা যেতে পারে, আর Docker তো পোর্ট পুরোপুরি UFW-কে পাশ কাটিয়ে প্রকাশ করে। খোদ সেবার কনফিগে বাঁধার সেটিংস এসব টিকে যায়:
- MySQL/MariaDB —
bind-address = 127.0.0.1; - PostgreSQL —
listen_addresses = 'localhost'; - Redis —
bind 127.0.0.1 ::1; - Docker Compose —
"127.0.0.1:5432:5432"হিসেবে প্রকাশ।
ফায়ারওয়াল উপর থেকে বীমা হিসেবে আসে, এর বদলে নয়।
স্পষ্ট না হলে প্রক্রিয়া খুঁজে বের করা
ss নাম আর pid দেয়। তারপর:
sudo systemctl status <pid>
sudo lsof -i :8080
প্রথম কমান্ড বলে প্রক্রিয়াটি কোন systemd ইউনিটের — সাধারণত সেটা কী আর দরকার কি না বোঝার জন্য যথেষ্ট। উঁচু পোর্টে শুনছে এমন অচেনা প্রক্রিয়া, যা সিস্টেম ডিরেক্টরির বাইরে থেকে চালু হয়েছে — ধরা যাক /tmp বা /dev/shm থেকে — এখন আর কনফিগারেশনের প্রশ্ন নয়, বরং আলাদা তদন্তের ভিত্তি।
বাইরে থেকে যাচাই বাধ্যতামূলক
ss «কী শুনছে»-র উত্তর দেয়, «কোথায় পৌঁছানো যায়»-এর নয়। এ দুইয়ের মাঝে দাঁড়িয়ে আছে ফায়ারওয়াল, NAT আর খোদ প্রদানকারীর নিয়ম। সৎ উত্তর কেবল অন্য যন্ত্র থেকে স্ক্যান করলেই মেলে:
nmap -Pn -p- 203.0.113.25
nmap -Pn -p- -6 2001:db8::1
দ্বিতীয় কমান্ডটি বাদ দেবেন না: প্রায় প্রতিটি VPS-এর IPv6 ঠিকানা আছে, তার নিয়ম আলাদা করে লেখা হয়, আর সেবা প্রোটোকলের দুই সংস্করণেই একসঙ্গে শোনে।
এটি একবারের যাচাই নয়
খোলা পোর্টের তালিকা নিজে থেকেই বদলায়। আপনি প্যাকেজ বসিয়েছেন আর সে সেবা এনেছে আর পোর্ট খুলেছে। প্যানেল হালনাগাদ করেছেন আর সে ডিফল্ট ফিরিয়ে দিয়েছে। কন্টেইনার চালিয়েছেন আর সে ফায়ারওয়ালকে পাশ কাটিয়ে পোর্ট প্রকাশ করেছে। একবারের যাচাই আজকের জন্য উত্তর দেয়, তার বেশি কিছু নয়।
মূল্য তালিকায় নয়, তার পরিবর্তনে: কাল যা ছিল না এমন নতুন পোর্ট হলো ছোট ও অত্যন্ত তথ্যবহুল সংকেত। ঠিক এভাবেই এটি দেখা উচিত — ইতিহাসসহ স্ন্যাপশট হিসেবে, স্মৃতি থেকে মনে করা ss ফলাফল হিসেবে নয়। নিচের ডেমো পাতা ঠিক তা-ই দেখায়।