EQVPS

Πώς ελέγχετε τις ανοιχτές θύρες ενός VPS: τι ακούει, τι βλέπει το internet και η έκπληξη του Docker

Δείτε κάθε θύρα στην οποία ακούει ο server, βρείτε τη διεργασία πίσω της, σαρώστε τον server από έξω όπως θα έκανε ένας επιτιθέμενος και κλείστε ό,τι δεν χρειάζεστε. Μαζί με τη θύρα του Docker που μένει ανοιχτή ακόμη και με ενεργό firewall. Κάθε αριθμός μετρήθηκε σε νέο server με Ubuntu 24.04.

Μια ανοιχτή και ξεχασμένη θύρα είναι ο κλασικός δρόμος μέσα σε έναν server: μια βάση δεδομένων σε δημόσια διεύθυνση, ένα dashboard αποσφαλμάτωσης, ένα container που δημοσίευσε μια θύρα που κανείς δεν ήθελε. Ο έλεγχος παίρνει ένα λεπτό αν ξέρετε δύο εντολές και μία παγίδα. Κάναμε όλα όσα ακολουθούν σε νέο server Ubuntu 24.04 από το image μας και τον σαρώσαμε από δεύτερο μηχάνημα, οπότε τα αποτελέσματα είναι αυτά που θα δείτε στον δικό σας server.

1. Τι ακούει

Η εντολή είναι το ss. Τα γράμματα σημαίνουν TCP, UDP, sockets σε ακρόαση, αριθμητικές θύρες και όνομα διεργασίας:

sudo ss -tulpn

Σε νέο server τυπώνει έξι γραμμές:

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Μόνο προγράμματα σε αυτόν τον server
0.0.0.0:…Οποιοσδήποτε μέσω IPv4, εκτός αν μπλοκάρει το firewall
[::]:…Οποιοσδήποτε μέσω IPv6 (συνήθως και IPv4)
10.0.0.5:… (συγκεκριμένη διεύθυνση)Όποιος φτάνει σε αυτή τη διεύθυνση

Άρα ο νέος server εκθέτει ακριβώς ένα πράγμα: SSH στη θύρα 22, μέσω IPv4 και IPv6. Ο DNS resolver στο 127.0.0.53 είναι ιδιωτικός.

Για να δείτε μόνο ό,τι θα μπορούσε να δει το internet, φιλτράρετε τις διευθύνσεις 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 και ένα socket του 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, βολικό σε scripts. Αν χρειάζεται να ελευθερώσετε τη θύρα, σταματήστε την υπηρεσία αντί να σκοτώσετε το PID, αλλιώς το systemd θα την επανεκκινήσει: sudo systemctl stop nginx.

3. Τι βλέπει το internet

Το ss δείχνει την οπτική του server. Η οπτική του internet μπορεί να διαφέρει, επειδή ενδιάμεσα υπάρχει firewall ή επειδή μια υπηρεσία είναι δεμένη στο 127.0.0.1. Για την πραγματική εικόνα, σαρώστε τον server από άλλο μηχάνημα, το laptop σας ή δεύτερο server. Το εργαλείο είναι το 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, η τρίτη μια λίστα. Στον νέο server μας, πριν από οποιοδήποτε firewall:

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: ο server απάντησε πως εκεί δεν ακούει τίποτα. Ασφαλές, αλλά επιβεβαιώνει ότι ο server υπάρχει και τι δεν τρέχει.
  • filtered: καμία απάντηση. Ένα firewall πέταξε το πακέτο. Ο σαρωτής δεν μπορεί να ξέρει αν υπάρχει υπηρεσία πίσω του.

Για μία θύρα χωρίς να εγκαταστήσετε τίποτα, το nc -zv ip-του-server 443 απαντά succeeded ή refused, και σε φιλτραρισμένη θύρα περιμένει ως το timeout. Για UDP προσθέστε -sU στο nmap και περιμένετε καθυστέρηση· στον server μας οι τρεις συνηθισμένες θύρες UDP, 53, 123 και 161, ήταν closed.

Μια σημείωση για τα πακέτα NAT: από το internet φτάνει μόνο η θύρα SSH που σας προωθήσαμε. Μια σάρωση της κοινόχρηστης διεύθυνσης δείχνει το δικό μας άκρο, όχι τον server σας, και οι άλλες θύρες είναι απρόσιτες ό,τι κι αν ακούει σε αυτές. Σε πακέτο με δική του διεύθυνση IPv4, κάθε ανοιχτή θύρα τη διαχειρίζεστε εσείς.

4. Κλείστε ό,τι δεν χρειάζεστε

Τρεις τρόποι, από τον καλύτερο στον πιο ευρύ.

Δέσιμο στο localhost. Αν μια υπηρεσία τη χρησιμοποιούν μόνο προγράμματα στον server, βάλτε την να ακούει στο 127.0.0.1. Ξεκινήσαμε μια μικρή web εφαρμογή με --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 όνομα αφαιρεί τον listener οριστικά. Ελέγξτε με ss ότι εξαφανίστηκε.

Ενεργοποιήστε το firewall. Επιτρέψτε πρώτα το 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. Περισσότερος χρόνος ανά θύρα για τον σαρωτή, λιγότερες πληροφορίες για τον server σας. Ο οδηγός μας για το UFW καλύπτει όρια ρυθμού, πρόσβαση από μία μόνο IP και IPv6.

Κοιτάξτε όμως την τρίτη γραμμή.

5. Η έκπληξη του Docker

Η θύρα 8081 έμεινε ανοιχτή με ενεργό firewall και χωρίς κανόνα που να την επιτρέπει. Ανήκει σε ένα container που ξεκινήσαμε με docker run -p 8081:80 nginx:alpine. Το Docker προσθέτει δικούς του κανόνες στο firewall του πυρήνα, και αυτοί αξιολογούνται πριν από τους κανόνες του ufw. Ο κανόνας που έγραψε στον server μας:

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

Κάθε πακέτο για τη θύρα 8081 προωθείται στο container πριν το ufw προλάβει να πει τη γνώμη του. Το ίδιο κάνει κάθε container με -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 ως reverse proxy μπροστά για τη δημόσια πλευρά, με HTTPS, ώστε οι μόνες ανοιχτές θύρες στον server να είναι οι 22, 80 και 443.

Λίστα ελέγχου μετά από κάθε αλλαγή

  1. sudo ss -tulpn: κάθε γραμμή με 0.0.0.0 ή [::] είναι κάτι που θέλατε να εκθέσετε;
  2. nmap ip-του-server από το laptop: ταιριάζουν οι ανοιχτές θύρες;
  3. Βάση δεδομένων, cache ή πίνακας διαχείρισης σε δημόσια διεύθυνση: μετακινήστε τα στο 127.0.0.1 ή πίσω από το firewall σήμερα.
  4. Κάθε εγγραφή ports: του Docker: ξεκινά με 127.0.0.1: αν δεν είναι η δημόσια θύρα web;
  5. SSH ανοιχτό σε όλους: προσθέστε fail2ban ή σύνδεση μόνο με κλειδί.

Στον Windows Server ο ίδιος έλεγχος είναι το Get-NetTCPConnection -State Listen, και οι κανόνες βρίσκονται στο Windows Firewall. Κάθε πακέτο Linux, από το Nano των $3 και πάνω, έχει έκδοση με δική του διεύθυνση IPv4, και εκεί ό,τι βλέπετε στο ss το βλέπει όλος ο κόσμος, μείον ό,τι σταματά το firewall σας.

Συχνές ερωτήσεις

Ποιες θύρες είναι ανοιχτές σε ένα νέο VPS;

Στο image Ubuntu 24.04 μας, μία: το SSH στη θύρα 22. Πέρα από αυτή ακούει μόνο ο τοπικός DNS resolver στις 127.0.0.53 και 127.0.0.54, στον οποίο το internet δεν φτάνει. Μια σάρωση και των 65.535 θυρών TCP από άλλο μηχάνημα βρήκε ακριβώς μία ανοιχτή θύρα.

Ποια είναι η διαφορά ανάμεσα σε closed και filtered θύρα;

Closed σημαίνει ότι ο server απάντησε πως εκεί δεν ακούει τίποτα, οπότε ο σαρωτής το μαθαίνει αμέσως. Filtered σημαίνει καμία απάντηση, αυτό κάνει ένα firewall όταν πετάει πακέτα. Και τα δύο κρατούν τους εισβολείς έξω, αλλά το filtered κρύβει επιπλέον ποιες υπηρεσίες υπάρχουν και κάνει μια πλήρη σάρωση περίπου δώδεκα φορές πιο αργή στον server μας.

Γιατί το ss δείχνει μια θύρα που το nmap λέει closed;

Η υπηρεσία ακούει μόνο στο 127.0.0.1, τη διεύθυνση loopback. Τα προγράμματα στον ίδιο τον server μπορούν να συνδεθούν, από έξω κανείς. Στο ss κοιτάξτε τη στήλη Local Address: το 127.0.0.1:8080 είναι ιδιωτικό, το 0.0.0.0:8080 ή [::]:8080 είναι προσβάσιμο από το internet αν το επιτρέπει το firewall.

Ενεργοποίησα το ufw, γιατί η θύρα του Docker είναι ακόμη ανοιχτή;

Το Docker γράφει δικούς του κανόνες firewall, που αξιολογούνται πριν από αυτούς του ufw. Ένα container που ξεκίνησε με -p 8081:80 ήταν προσβάσιμο από έξω στον server μας με ενεργό ufw και χωρίς κανόνα για τη 8081. Δημοσιεύστε στο localhost, -p 127.0.0.1:8081:80, και βάλτε nginx ή Caddy μπροστά για τη δημόσια πλευρά.

Πώς ελέγχω μια θύρα από τον δικό μου υπολογιστή;

Τρέξτε nc -zv ip-του-server 443 για μία θύρα ή εγκαταστήστε το nmap και τρέξτε nmap ip-του-server για τις χίλιες πιο συνηθισμένες. Σε πακέτο NAT από το internet απαντά μόνο η θύρα SSH που σας προωθήσαμε· όλα τα άλλα είναι απρόσιτα σκόπιμα.

Σχόλια

Δεν υπάρχουν ακόμη σχόλια. Γίνετε ο πρώτος.

Αφήστε ένα σχόλιο

Τα σχόλια ελέγχονται πριν εμφανιστούν.