En öppen och bortglömd port är den klassiska vägen in i en server: en databas på en publik adress, en felsökningspanel, en container som publicerade en port som ingen ville publicera. Kontrollen tar en minut om du kan två kommandon och en fälla. Vi körde allt nedan på en ny Ubuntu 24.04-server från vår avbild och skannade den från en andra maskin, så utskrifterna är det du kommer att se på din egen server.
1. Vad som lyssnar
Kommandot är ss. Bokstäverna står för TCP, UDP, lyssnande socketar, numeriska portar och processnamn:
sudo ss -tulpn
På en ny server skriver det ut sex rader:
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
Kolumnen som spelar roll är Local Address. Den säger vem som kan ansluta:
| Adress | Vem som når den |
|---|---|
127.0.0.1:… eller 127.0.0.53 | Bara program på den här servern |
0.0.0.0:… | Vem som helst över IPv4, om inte brandväggen blockerar |
[::]:… | Vem som helst över IPv6 (och oftast IPv4 också) |
10.0.0.5:… (en specifik adress) | Vem som helst som når den adressen |
Den nya servern exponerar alltså exakt en sak: SSH på port 22, över IPv4 och IPv6. DNS-resolvern på 127.0.0.53 är privat.
För att bara lista det internet skulle kunna se, filtrera bort loopback-adresserna:
sudo ss -tlnp | awk 'NR>1 && $4 !~ /^(127\.|\[::1\])/ {print $4, $6}'
Kör det efter varje installation. Vi installerade nginx, Docker och en liten Python-app, och listan växte från 2 rader till 10, bland annat en docker-proxy på 0.0.0.0:8081 och en containerd-socket på en slumpmässig localhost-port.
2. Vilken process som äger en port
När en port är upptagen och du vill veta av vem:
sudo lsof -i :80 -P -n
sudo fuser 80/tcp
sudo ss -tlnp 'sport = :80'
lsof är lättast att läsa. För nginx visade det en masterprocess som root och en worker som www-data, båda på *:80, för IPv4 och IPv6. fuser skriver bara ut PID:er, praktiskt i skript. Behöver du frigöra porten, stoppa tjänsten i stället för att döda PID:en, annars startar systemd om den: sudo systemctl stop nginx.
3. Vad internet ser
ss visar serverns perspektiv. Internets perspektiv kan skilja sig, eftersom en brandvägg sitter emellan eller en tjänst är bunden till 127.0.0.1. För den verkliga bilden, skanna servern från en annan maskin, din laptop eller en andra server. Verktyget är nmap (apt install nmap, eller installationsprogrammet från nmap.org på Windows och macOS).
nmap your-server-ip
nmap -p- your-server-ip
nmap -p 22,80,443,3306 your-server-ip
Den första formen kontrollerar de 1 000 vanligaste portarna, den andra alla 65 535, den tredje en lista. På vår nya server, före någon brandvägg:
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 fullständiga skanningen av 65 535 portar tog 8,9 sekunder och hittade samma enda port. Stängda portar svarar direkt med en reset, därför går det snabbt att skanna dem.
Tre tillstånd spelar roll:
- open: ett program accepterade anslutningen. Det här är din attackyta.
- closed: servern svarade att inget lyssnar där. Säkert, men det bekräftar att servern finns och vad den inte kör.
- filtered: inget svar. En brandvägg kastade paketet. Skannern kan inte veta om en tjänst finns bakom.
För en enda port utan att installera något svarar nc -zv server-ip 443 med succeeded eller refused, och hänger kvar till timeouten på en filtrerad port. För UDP lägger du till -sU i nmap och räknar med väntan; på vår server var de tre vanliga UDP-portarna, 53, 123 och 161, closed.
En anmärkning om NAT-abonnemang: från internet nås bara den SSH-port vi vidarebefordrat till dig. En skanning av den delade adressen visar vår kant, inte din server, och övriga portar är onåbara oavsett vad som lyssnar på dem. På ett abonnemang med egen IPv4-adress hanterar du varje öppen port själv.
4. Stäng det du inte behöver
Tre sätt, från bäst till bredast.
Bind till localhost. Om bara program på servern använder en tjänst, låt den lyssna på 127.0.0.1. Vi startade en liten webbapp med --bind 127.0.0.1 8080: ss visade den på 127.0.0.1:8080, och nmap utifrån rapporterade 8080/tcp closed. För databaser är det rätt standard: Redis, MySQL och PostgreSQL lyssnar på localhost direkt efter installation på Ubuntu, och våra guider för Redis och MySQL låter det vara så.
Stoppa tjänsten. sudo systemctl disable --now namn tar bort lyssnaren för gott. Kontrollera med ss att den är borta.
Slå på brandväggen. Tillåt SSH först, sedan det du tillhandahåller, och aktivera sedan:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw enable
sudo ufw status verbose
Skanningen utifrån förändrades helt:
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
Varje icke tillåten port gick från closed till filtered, och den fullständiga skanningen av 65 535 portar tog nu 110 sekunder i stället för 8,9. Mer tid per port för skannern, mindre information om din server. Vår UFW-guide tar upp hastighetsbegränsning, att tillåta en enda IP och IPv6.
Men titta på tredje raden.
5. Docker-överraskningen
Port 8081 förblev öppen med brandväggen på och utan någon regel som tillät den. Porten tillhör en container som vi startade med docker run -p 8081:80 nginx:alpine. Docker lägger till egna regler i kärnans brandvägg, och de utvärderas före ufw:s. Regeln den skrev på vår server:
-A DOCKER ! -i docker0 -p tcp --dport 8081 -j DNAT --to-destination 172.17.0.2:80
Varje paket till port 8081 vidarebefordras in i containern innan ufw får säga sitt. Det gör varje container med -p eller en ports:-post, och ss visar det ärligt som docker-proxy på 0.0.0.0:8081.
Lösningen är att bara publicera 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 visade ss 127.0.0.1:8081, Docker-regeln fick -d 127.0.0.1/32, och skanningen utifrån rapporterade 8081/tcp filtered. Sätt nginx som omvänd proxy framför för den publika sidan, med HTTPS, så att de enda öppna portarna på servern är 22, 80 och 443.
Checklista efter varje ändring
sudo ss -tulpn: är varje rad med0.0.0.0eller[::]något du ville exponera?nmap server-ipfrån din laptop: stämmer de öppna portarna?- En databas, cache eller adminpanel på en publik adress: flytta den till
127.0.0.1eller bakom brandväggen i dag. - Varje Docker-
ports:-post: börjar den med127.0.0.1:om det inte är den publika webbporten? - SSH öppen för alla: lägg till fail2ban eller inloggning endast med nyckel.
På Windows Server är samma kontroll Get-NetTCPConnection -State Listen, och reglerna finns i Windows-brandväggen. Varje Linux-abonnemang, från Nano för $3 och uppåt, finns i en version med egen IPv4-adress, och där ser världen det du ser i ss, minus din brandvägg.
Kommentarer
Inga kommentarer än. Bli först.