Direct naar de inhoud

Cookie-instellingen

Kies per soort welke cookies je toestaat. Je kunt je keuze altijd wijzigen via Cookie-instellingen onderaan elke pagina. Privacyverklaring

Noodzakelijk

Altijd aan

Nodig om in te loggen, je winkelwagen te bewaren en je keuzes te onthouden. Deze staan altijd aan.

Welke cookies?
  • weboke_sessie, weboke_klant, weboke_remember: je sessie en ingelogd blijven
  • weboke_basket: je winkelwagen
  • wkBtwIncl: prijzen met of zonder btw tonen
  • wok_cookies: je cookiekeuze, 12 maanden

Meet welke advertentie tot een bezoek of bestelling leidt, zodat we niet betalen voor advertenties die niets doen.

Welke cookies?
  • Google Ads via Google Tag Manager (_gcl_au, _gcl_aw), tot 90 dagen
  • OpenAI Ads, advertenties in ChatGPT
  • wok_aff: via welke partner je bij ons kwam (affiliateprogramma), 60 dagen

4,6

Land en taal

Elk land heeft zijn eigen site, met prijzen en btw van dat land.

Bekijken

Module 5 · 5.1

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:

PoortProtocolDienst
22TCPSSH
80TCPhttp (webserver)
443TCP en UDPhttps (UDP voor HTTP/3)
25TCPmail tussen mailservers (SMTP)
3306TCPMySQL en MariaDB
5432TCPPostgreSQL
6379TCPRedis

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.

AdresBetekenis
0.0.0.0Alle 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.54Ook loopback; hier luistert de lokale DNS-hulp van systemd-resolved
192.0.2.10Alleen 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:

ProgrammaInstellingBestand (Debian/Ubuntu)
MariaDB/MySQLbind-address = 127.0.0.1/etc/mysql/mariadb.conf.d/50-server.cnf
PostgreSQLlisten_addresses = 'localhost'/etc/postgresql/<versie>/main/postgresql.conf
Redisbind 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 -tulpn laat zien welk programma op welk adres en welke poort luistert.
  • 0.0.0.0 en [::] betekenen "alle adressen", 127.0.0.1 en [::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 ss ziet de firewall niet.

Quiz

1. In ss -tulpn staat 127.0.0.1:3306 bij mariadbd. Wat betekent dat?



2. Redis luistert op 0.0.0.0:6379. Je firewall laat 6379 niet toe. Wat is de beste aanpak?



3. Je test van buitenaf poort 5432 en de verbinding blijft 3 seconden hangen en mislukt dan. Wat is de waarschijnlijke status?



4. Waarom moet je een open poort van buitenaf controleren en niet alleen met ss op de server?



5. Je firewall heeft regels voor IPv4, maar je server heeft ook een IPv6-adres. Redis luistert op [::]:6379. Wat is het risico?



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.

Opdracht Z5.1: Databasepoorten dicht van buiten

We loggen niet in en proberen geen wachtwoord of sleutel. Eerst laat je zien dat de server van jou is: klik op "Toon mijn code" en zet een bestand /.well-known/weboke-cursus-<code>.txt met alleen die code op de webserver van je hostnaam. We halen het rechtstreeks op bij elk IP-adres dat we controleren (IPv4 en IPv6 apart); een TXT-record telt hier niet. De controle komt van heavy.webawere.nl (185.158.167.16 en 2a07:ae80:100:0:185:158:167:16), niet van onze webserver. Alleen voor aangemelde cursisten; per server hoogstens 6 controles per uur. We maken alleen een TCP-verbinding naar de poorten 3306, 5432, 6379, 9200, 27017 en 2375 (IPv4 en IPv6) en sturen niets.




Wat je invult en wat we vinden, slaan we niet op. Je browser onthoudt je antwoorden en of je de opdracht hebt gehaald. Ben je aangemeld, dan bewaren we alleen dat je de opdracht (bijna) goed had in Mijn cursussen; daar kun je het ook verwijderen.

Verder lezen

Even geduld…

Stel je domeinen in

Regel per domein de nameservers, de koppeling aan je hosting en wie de eigenaar wordt.

Je domeinen laden…