En åben og glemt port er den klassiske vej ind i en server: en database på en offentlig adresse, et debug-dashboard, en container, der udgav en port, som ingen ville udgive. Tjekket tager et minut, når du kender to kommandoer og én fælde. Vi kørte alt nedenfor på en ny Ubuntu 24.04-server fra vores image og scannede den fra en anden maskine, så outputtet er det, du vil se på din egen server.
1. Hvad der lytter
Kommandoen er ss. Bogstaverne står for TCP, UDP, lyttende sockets, numeriske porte og procesnavn:
sudo ss -tulpn
På en ny server udskriver den seks linjer:
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
Kolonnen, der betyder noget, er Local Address. Den fortæller, hvem der kan forbinde:
| Adresse | Hvem der kan nå den |
|---|---|
127.0.0.1:… eller 127.0.0.53 | Kun programmer på denne server |
0.0.0.0:… | Alle over IPv4, medmindre firewallen blokerer |
[::]:… | Alle over IPv6 (og som regel også IPv4) |
10.0.0.5:… (en bestemt adresse) | Alle, der kan nå den adresse |
Den nye server eksponerer altså præcis én ting: SSH på port 22, over IPv4 og IPv6. DNS-resolveren på 127.0.0.53 er privat.
For kun at liste det, internettet kunne se, filtrerer du loopback-adresserne fra:
sudo ss -tlnp | awk 'NR>1 && $4 !~ /^(127\.|\[::1\])/ {print $4, $6}'
Kør det efter hver installation. Vi installerede nginx, Docker og en lille Python-app, og listen voksede fra 2 linjer til 10, blandt andet en docker-proxy på 0.0.0.0:8081 og en containerd-socket på en tilfældig localhost-port.
2. Hvilken proces der ejer en port
Når en port er optaget, og du vil vide af hvem:
sudo lsof -i :80 -P -n
sudo fuser 80/tcp
sudo ss -tlnp 'sport = :80'
lsof er nemmest at læse. For nginx viste den en masterproces som root og en worker som www-data, begge på *:80, for IPv4 og IPv6. fuser udskriver kun PID'er, praktisk i scripts. Skal du frigøre porten, så stop tjenesten i stedet for at dræbe PID'en, ellers genstarter systemd den: sudo systemctl stop nginx.
3. Hvad internettet ser
ss viser serverens perspektiv. Internettets kan være anderledes, fordi en firewall sidder imellem, eller fordi en tjeneste er bundet til 127.0.0.1. For at se det reelle billede skal du scanne serveren fra en anden maskine, din bærbare eller en anden server. Værktøjet er nmap (apt install nmap, eller installationsprogrammet fra nmap.org på Windows og macOS).
nmap your-server-ip
nmap -p- your-server-ip
nmap -p 22,80,443,3306 your-server-ip
Den første form tjekker de 1.000 mest almindelige porte, den anden alle 65.535, den tredje en liste. På vores nye server, før nogen 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
Den fulde scanning af 65.535 porte tog 8,9 sekunder og fandt den samme ene port. Lukkede porte svarer straks med en reset, derfor er de hurtige at scanne.
Tre tilstande tæller:
- open: et program accepterede forbindelsen. Det er din angrebsflade.
- closed: serveren svarede, at intet lytter der. Sikkert, men det bekræfter, at serveren findes, og hvad den ikke kører.
- filtered: intet svar. En firewall smed pakken væk. Scanneren kan ikke vide, om der er en tjeneste bagved.
For en enkelt port uden at installere noget svarer nc -zv server-ip 443 med succeeded eller refused, og den hænger til timeout på en filtreret port. For UDP tilføjer du -sU til nmap og må forvente at vente; på vores server var de tre almindelige UDP-porte, 53, 123 og 161, closed.
En bemærkning om NAT-planer: fra internettet kan kun den SSH-port, vi har videresendt til dig, nås. En scanning af den delte adresse viser vores kant, ikke din server, og de øvrige porte kan ikke nås, uanset hvad der lytter på dem. På en plan med egen IPv4-adresse styrer du selv hver åben port.
4. Luk det, du ikke har brug for
Tre måder, fra bedst til bredest.
Bind til localhost. Hvis kun programmer på serveren bruger en tjeneste, så lad den lytte på 127.0.0.1. Vi startede en lille webapp med --bind 127.0.0.1 8080: ss viste den på 127.0.0.1:8080, og nmap udefra meldte 8080/tcp closed. For databaser er det den rigtige standard: Redis, MySQL og PostgreSQL lytter på localhost fra start på Ubuntu, og vores guides til Redis og MySQL lader det være sådan.
Stop tjenesten. sudo systemctl disable --now navn fjerner lytteren for altid. Tjek med ss, at den er væk.
Slå firewallen til. Tillad først SSH, derefter det, du leverer, og aktivér så:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw enable
sudo ufw status verbose
Scanningen udefra ændrede sig fuldstændigt:
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
Hver ikke-tilladt port gik fra closed til filtered, og den fulde scanning af 65.535 porte tog nu 110 sekunder i stedet for 8,9. Mere tid pr. port for scanneren, mindre information om din server. Vores UFW-guide dækker hastighedsbegrænsning, at tillade en enkelt IP og IPv6.
Men se på tredje linje.
5. Docker-overraskelsen
Port 8081 forblev åben med firewallen slået til og uden en regel, der tillod den. Porten tilhører en container, vi startede med docker run -p 8081:80 nginx:alpine. Docker tilføjer sine egne regler til kernens firewall, og de evalueres før ufw's. Reglen, den skrev på vores server:
-A DOCKER ! -i docker0 -p tcp --dport 8081 -j DNAT --to-destination 172.17.0.2:80
Hver pakke til port 8081 sendes videre ind i containeren, før ufw får noget at skulle have sagt. Det gør hver container med -p eller en ports:-post, og ss viser det ærligt som docker-proxy på 0.0.0.0:8081.
Løsningen er kun at udgive på localhost:
docker rm -f web
docker run -d --name web -p 127.0.0.1:8081:80 nginx:alpine
I Compose skriver du "127.0.0.1:8081:80" under ports:. Efter ændringen viste ss 127.0.0.1:8081, Docker-reglen fik -d 127.0.0.1/32, og scanningen udefra meldte 8081/tcp filtered. Sæt nginx som reverse proxy foran til den offentlige side, med HTTPS, så de eneste åbne porte på serveren er 22, 80 og 443.
Tjekliste efter hver ændring
sudo ss -tulpn: er hver linje med0.0.0.0eller[::]noget, du ville eksponere?nmap server-ipfra din bærbare: passer de åbne porte?- En database, cache eller et adminpanel på en offentlig adresse: flyt det til
127.0.0.1eller bag firewallen i dag. - Hver Docker-
ports:-post: starter den med127.0.0.1:, hvis det ikke er den offentlige webport? - SSH åben for alle: tilføj fail2ban eller login kun med nøgle.
På Windows Server er det samme tjek Get-NetTCPConnection -State Listen, og reglerne findes i Windows Firewall. Hver Linux-plan, fra Nano til $3 og op, findes i en version med egen IPv4-adresse, og der ser verden det, du ser i ss, minus din firewall.
Kommentarer
Ingen kommentarer endnu. Vær den første.