खुले पोर्टों की सूची आपके सर्वर तक पहुँचने के रास्तों की सूची है। बाकी सब — फ़ायरवॉल, 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 आउटपुट की तरह। नीचे का डेमो पेज यही दिखाता है।