Poorten en luisterende diensten
Module 5: Het netwerk afschermen · Leestijd: 10 minuten
Leerdoel: Na deze les kun je zien welke diensten op je server luisteren en op welk adres, het verschil uitleggen tussen 0.0.0.0 en 127.0.0.1, en van buitenaf controleren wat iedereen op internet van je server ziet.
Kernbegrippen: poort, TCP en UDP, luisteren, ss -tulpn, 0.0.0.0 en [::], 127.0.0.1 en [::1], bind-address, open, dicht en gefilterd, aanvalsoppervlak, scanners
Een IP-adres met 65.535 deuren
Je server heeft een IP-adres, bijvoorbeeld 192.0.2.10 en 2001:db8::10. Op dat adres kunnen verschillende programma's tegelijk bereikbaar zijn, elk op een eigen poort: een nummer van 1 tot 65.535. Een programma dat verbindingen aanneemt, luistert op een poort. Een paar bekende:
| Poort | Protocol | Dienst |
|---|---|---|
| 22 | TCP | SSH |
| 80 | TCP | http (webserver) |
| 443 | TCP en UDP | https (UDP voor HTTP/3) |
| 25 | TCP | mail tussen mailservers (SMTP) |
| 3306 | TCP | MySQL en MariaDB |
| 5432 | TCP | PostgreSQL |
| 6379 | TCP | Redis |
TCP is het protocol voor verbindingen die betrouwbaar moeten aankomen (web, SSH, databases). UDP is voor snelle losse pakketjes (DNS, VPN's als WireGuard, HTTP/3). Een dienst luistert op TCP, UDP of allebei.
Elke luisterende poort is een deur naar je server. Achter elke deur zit software die fouten kan bevatten. Het geheel van deuren die van buiten bereikbaar zijn, heet je aanvalsoppervlak. Hoe kleiner, hoe beter: een server met een website heeft van buiten alleen 22, 80 en 443 nodig.
Kijken wat er luistert: ss
Het commando ss (socket statistics) laat zien wat er op je server luistert. Met de opties -t (TCP), -u (UDP), -l (alleen luisterend), -p (welk programma) en -n (nummers, geen namen):
anna@web1:~$ sudo ss -tulpn
Netid State Local Address:Port Peer Address:Port Process
udp UNCONN 127.0.0.54:53 0.0.0.0:* users:(("systemd-resolve",pid=402,fd=16))
tcp LISTEN 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=611,fd=3))
tcp LISTEN 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=902,fd=6))
tcp LISTEN 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=902,fd=7))
tcp LISTEN 127.0.0.1:3306 0.0.0.0:* users:(("mariadbd",pid=755,fd=21))
tcp LISTEN 0.0.0.0:6379 0.0.0.0:* users:(("redis-server",pid=780,fd=6))
tcp LISTEN [::]:22 [::]:* users:(("sshd",pid=611,fd=4))
tcp LISTEN [::]:80 [::]:* users:(("nginx",pid=902,fd=8))
tcp LISTEN [::]:443 [::]:* users:(("nginx",pid=902,fd=9))De belangrijkste kolom is Local Address: het adres waarop het programma luistert.
| Adres | Betekenis |
|---|---|
0.0.0.0 | Alle IPv4-adressen van de server, dus ook het publieke adres: bereikbaar van buiten (tenzij een firewall het tegenhoudt) |
[::] | Alle IPv6-adressen: idem voor IPv6 |
127.0.0.1 of [::1] | Alleen de server zelf (loopback): van buiten nooit bereikbaar |
127.0.0.53, 127.0.0.54 | Ook loopback; hier luistert de lokale DNS-hulp van systemd-resolved |
192.0.2.10 | Alleen dat ene adres |
In het voorbeeld hierboven is MariaDB in orde: hij luistert op 127.0.0.1, dus alleen programma's op de server zelf (je website) kunnen erbij. Maar Redis luistert op 0.0.0.0:6379. Als de firewall niet goed staat, kan heel internet erbij. Dat is precies het soort fout waar deze les over gaat.
Luisteren op het juiste adres
Een database, cache of beheerpaneel hoort bijna nooit van buiten bereikbaar te zijn. De eerste en beste verdediging is dat de dienst alleen op loopback luistert. Een firewall (les 5.2) is de tweede laag; die kan per ongeluk uitstaan of niet gelden (bijvoorbeeld bij Docker, les 9.3).
Waar je dat instelt, verschilt per programma:
| Programma | Instelling | Bestand (Debian/Ubuntu) |
|---|---|---|
| MariaDB/MySQL | bind-address = 127.0.0.1 | /etc/mysql/mariadb.conf.d/50-server.cnf |
| PostgreSQL | listen_addresses = 'localhost' | /etc/postgresql/<versie>/main/postgresql.conf |
| Redis | bind 127.0.0.1 -::1 en protected-mode yes | /etc/redis/redis.conf |
De pakketten van Debian en Ubuntu zetten deze diensten standaard al op localhost. Het gaat meestal mis als iemand een handleiding volgt die zegt "zet bind-address op 0.0.0.0 om van buiten te verbinden". Wil je zelf vanaf je laptop bij de database, gebruik dan een SSH-tunnel (les 2.3): de poort blijft dicht, en alleen wie via SSH binnenkomt, kan erbij.
Na een wijziging herstart je de dienst en kijk je opnieuw met ss -tulpn.
Open, dicht en gefilterd
Van buitenaf gezien kan een poort drie dingen zijn:
- Open: er luistert iets en de verbinding lukt.
- Dicht (closed): er luistert niets, of een firewall weigert actief. De server stuurt meteen een "nee" terug (bij TCP een RST-pakketje). Een verbinding faalt direct met "Connection refused".
- Gefilterd (filtered): een firewall gooit het pakketje stil weg. De verbinding blijft hangen tot een time-out.
Voor je database zijn dicht en gefilterd allebei goed: niemand komt erbij. Het verschil vertelt je alleen waarom: gefilterd betekent bijna altijd dat je firewall het tegenhoudt.
Van buitenaf kijken
ss laat zien wat er op de server luistert, maar niet wat er van buiten bereikbaar is. Daarvoor zit er nog een firewall tussen, bij je aanbieder soms ook nog een netwerkfirewall. De enige echte controle is daarom: kijk van buitenaf, vanaf een andere computer.
Vanaf je eigen computer (niet vanaf de server zelf, want dan ga je via loopback) kan dat met nc (netcat) voor één poort:
anna@laptop:~$ nc -vz -w 3 192.0.2.10 6379
nc: connect to 192.0.2.10 port 6379 (tcp) failed: Connection refused
anna@laptop:~$ nc -vz -w 3 192.0.2.10 22
Connection to 192.0.2.10 22 port [tcp/ssh] succeeded!Op Windows doet PowerShell hetzelfde met Test-NetConnection 192.0.2.10 -Port 6379. Een poortscanner als nmap kan meer poorten tegelijk bekijken; gebruik zo'n scanner alleen op je eigen server.
Vergeet IPv6 niet. Een veelgemaakte fout is een firewall die alleen voor IPv4 regels heeft, terwijl de dienst ook op [::] luistert. Test dus ook het IPv6-adres: nc -6 -vz -w 3 2001:db8::10 6379.
Waarom dit zo belangrijk is
Je server wordt vanaf de eerste minuut gescand. Zoekmachines voor apparaten en diensten op internet, en bots van criminelen, proberen continu alle IPv4-adressen op bekende poorten. Een open Redis zonder wachtwoord, een Elasticsearch-cluster of een MongoDB zonder toegangscontrole wordt binnen korte tijd gevonden. Datalekken door open databases en open zoekclusters komen geregeld in het nieuws, en het gaat bijna altijd om precies deze fout: een dienst die voor intern gebruik bedoeld was, luisterde op alle adressen.
Ook de poort van SSH wordt de hele dag aangeklopt. Dat is normaal en met sleutels (les 2.2) en fail2ban (les 5.3) geen probleem.
De cursuscontrole
In de opdracht bij deze les controleert het cursusprogramma van buitenaf vijf vaste databasepoorten van je server: 3306 (MySQL/MariaDB), 5432 (PostgreSQL), 6379 (Redis), 9200 (Elasticsearch/OpenSearch) en 27017 (MongoDB). Het programma probeert alleen of er een verbinding tot stand komt, stuurt geen gegevens en logt nergens in. Het scant geen andere poorten. De controles komen van het IP-adres dat in de opdracht staat, zodat je ze in je eigen logboek kunt herkennen. Een adres kan maar een paar keer per uur gecontroleerd worden.
Op AlmaLinux en Rocky Linux
ss werkt hetzelfde. Bestanden van diensten staan op andere plekken (bijvoorbeeld /etc/my.cnf.d/ voor MariaDB, /var/lib/pgsql/data/postgresql.conf voor PostgreSQL). Daarnaast kan SELinux een dienst tegenhouden die op een ongebruikelijke poort wil luisteren; dat zie je dan in journalctl (les 6.2) en niet in ss.
Samenvatting
- Elke luisterende poort is een deur; houd van buiten alleen open wat echt nodig is (meestal 22, 80 en 443).
sudo ss -tulpnlaat zien welk programma op welk adres en welke poort luistert.0.0.0.0en[::]betekenen "alle adressen",127.0.0.1en[::1]betekenen "alleen de server zelf". Databases, caches en zoekclusters horen op loopback.- Dicht en gefilterd zijn allebei goed voor een database; open is fout.
- Controleer altijd van buitenaf, voor IPv4 én IPv6, want
ssziet de firewall niet.
Quiz
Opdracht
Opdracht Z5.1: Databasepoorten dicht van buiten. Draai sudo ss -tulpn op je server en zoek uit op welke adressen je diensten luisteren. Laat daarna het cursusprogramma van buitenaf controleren dat de poorten 3306, 5432, 6379, 9200 en 27017 van je server niet bereikbaar zijn, voor IPv4 en (als je server een AAAA-record heeft) IPv6. Vul ook in welke diensten bij jou op 0.0.0.0 of [::] luisteren. Het programma maakt alleen een verbinding naar die vijf poorten en stuurt niets.
