Un port deschis și uitat este calea clasică de intrare într-un server: o bază de date pe o adresă publică, un panou de depanare, un container care a publicat un port pe care nu-l voia nimeni publicat. Verificarea durează un minut dacă știi două comenzi și o capcană. Am făcut totul mai jos pe un server Ubuntu 24.04 nou din imaginea noastră și l-am scanat de pe o a doua mașină, așa că rezultatele sunt cele pe care le vei vedea pe propriul server.
1. Ce ascultă
Comanda este ss. Literele înseamnă TCP, UDP, socket-uri care ascultă, porturi numerice și numele procesului:
sudo ss -tulpn
Pe un server nou afișează șase rânduri:
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
Coloana care contează este Local Address. Îți spune cine se poate conecta:
| Adresă | Cine ajunge la ea |
|---|---|
127.0.0.1:… sau 127.0.0.53 | Doar programele de pe acest server |
0.0.0.0:… | Oricine prin IPv4, dacă firewall-ul nu blochează |
[::]:… | Oricine prin IPv6 (de obicei și IPv4) |
10.0.0.5:… (o adresă anume) | Oricine poate ajunge la acea adresă |
Serverul nou expune deci un singur lucru: SSH pe portul 22, prin IPv4 și IPv6. Resolverul DNS de pe 127.0.0.53 este privat.
Ca să listezi doar ce ar putea vedea internetul, filtrează adresele de loopback:
sudo ss -tlnp | awk 'NR>1 && $4 !~ /^(127\.|\[::1\])/ {print $4, $6}'
Rulează asta după fiecare instalare. Am instalat nginx, Docker și o mică aplicație Python, iar lista a crescut de la 2 rânduri la 10, printre care un docker-proxy pe 0.0.0.0:8081 și un socket containerd pe un port localhost aleatoriu.
2. Ce proces ocupă un port
Când un port e ocupat și vrei să afli de cine:
sudo lsof -i :80 -P -n
sudo fuser 80/tcp
sudo ss -tlnp 'sport = :80'
lsof e cel mai ușor de citit. Pentru nginx a arătat un proces master ca root și un worker ca www-data, ambele pe *:80, pentru IPv4 și IPv6. fuser afișează doar PID-urile, util în scripturi. Dacă trebuie să eliberezi portul, oprește serviciul în loc să omori PID-ul, altfel systemd îl repornește: sudo systemctl stop nginx.
3. Ce vede internetul
ss arată perspectiva serverului. Perspectiva internetului poate fi alta, pentru că între ele stă un firewall sau un serviciu e legat de 127.0.0.1. Pentru imaginea reală, scanează serverul de pe altă mașină, laptopul tău sau un al doilea server. Unealta este nmap (apt install nmap, sau installerul de pe nmap.org pentru Windows și macOS).
nmap your-server-ip
nmap -p- your-server-ip
nmap -p 22,80,443,3306 your-server-ip
Prima formă verifică cele mai comune 1.000 de porturi, a doua toate cele 65.535, a treia o listă. Pe serverul nostru nou, înainte de orice 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
Scanarea completă a celor 65.535 de porturi a durat 8,9 secunde și a găsit același port unic. Porturile închise răspund imediat cu un reset, de aceea scanarea lor e rapidă.
Contează trei stări:
- open: un program a acceptat conexiunea. Asta e suprafața ta de atac.
- closed: serverul a răspuns că acolo nu ascultă nimic. Sigur, dar confirmă că serverul există și ce nu rulează.
- filtered: niciun răspuns. Un firewall a aruncat pachetul. Scannerul nu poate ști dacă în spate e un serviciu.
Pentru un singur port fără să instalezi nimic, nc -zv ip-server 443 răspunde succeeded sau refused, iar pe un port filtrat așteaptă până la expirare. Pentru UDP adaugă -sU la nmap și pregătește-te de așteptare; pe serverul nostru cele trei porturi UDP comune, 53, 123 și 161, erau closed.
O notă pentru planurile NAT: de pe internet ajunge doar portul SSH pe care ți l-am redirecționat. O scanare a adresei comune arată marginea rețelei noastre, nu serverul tău, iar celelalte porturi sunt inaccesibile indiferent ce ascultă pe ele. Pe un plan cu adresă IPv4 proprie, fiecare port deschis îl gestionezi tu.
4. Închide ce nu-ți trebuie
Trei metode, de la cea mai bună la cea mai largă.
Leagă de localhost. Dacă doar programele de pe server folosesc un serviciu, fă-l să asculte pe 127.0.0.1. Am pornit o mică aplicație web cu --bind 127.0.0.1 8080: ss a arătat-o pe 127.0.0.1:8080, iar nmap din exterior a raportat 8080/tcp closed. Pentru baze de date asta e setarea implicită corectă: Redis, MySQL și PostgreSQL ascultă pe localhost din start pe Ubuntu, iar ghidurile noastre pentru Redis și MySQL le lasă așa.
Oprește serviciul. sudo systemctl disable --now nume elimină definitiv ascultătorul. Verifică cu ss că a dispărut.
Pornește firewall-ul. Permite întâi SSH, apoi ce servești, apoi activează:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw enable
sudo ufw status verbose
Scanarea din exterior s-a schimbat complet:
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
Fiecare port nepermis a trecut din closed în filtered, iar scanarea completă a celor 65.535 de porturi a durat acum 110 secunde în loc de 8,9. Mai mult timp pe port pentru scanner, mai puține informații despre serverul tău. Ghidul nostru UFW acoperă limitarea ratei, permiterea unui singur IP și IPv6.
Dar uită-te la al treilea rând.
5. Surpriza Docker
Portul 8081 a rămas deschis cu firewall-ul pornit și fără nicio regulă care să-l permită. Portul aparține unui container pornit cu docker run -p 8081:80 nginx:alpine. Docker adaugă propriile reguli în firewall-ul kernelului, iar acestea sunt evaluate înaintea celor ufw. Regula pe care a scris-o pe serverul nostru:
-A DOCKER ! -i docker0 -p tcp --dport 8081 -j DNAT --to-destination 172.17.0.2:80
Orice pachet către portul 8081 este redirecționat în container înainte ca ufw să aibă un cuvânt de spus. Așa face orice container cu -p sau o intrare ports:, iar ss îl arată cinstit ca docker-proxy pe 0.0.0.0:8081.
Soluția e să publici doar pe localhost:
docker rm -f web
docker run -d --name web -p 127.0.0.1:8081:80 nginx:alpine
În Compose scrie "127.0.0.1:8081:80" sub ports:. După schimbare, ss a arătat 127.0.0.1:8081, regula Docker a primit -d 127.0.0.1/32, iar scanarea din exterior a raportat 8081/tcp filtered. Pune nginx ca reverse proxy în față pentru partea publică, cu HTTPS, ca singurele porturi deschise pe server să fie 22, 80 și 443.
Listă de verificare după fiecare schimbare
sudo ss -tulpn: fiecare rând cu0.0.0.0sau[::]e ceva ce ai vrut să expui?nmap ip-serverde pe laptop: porturile deschise se potrivesc?- O bază de date, un cache sau un panou de administrare pe o adresă publică: mută-l azi pe
127.0.0.1sau în spatele firewall-ului. - Fiecare intrare
ports:din Docker: începe cu127.0.0.1:dacă nu e portul web public? - SSH deschis tuturor: adaugă fail2ban sau autentificare doar cu cheie.
Pe Windows Server aceeași verificare este Get-NetTCPConnection -State Listen, iar regulile stau în Windows Firewall. Fiecare plan Linux, de la Nano la $3 în sus, are o variantă cu adresă IPv4 proprie, iar acolo ce vezi în ss vede și restul lumii, minus ce oprește firewall-ul tău.
Comentarii
Încă nu există comentarii. Fii primul.