TeamSpeak-3-server beschermen tegen DDoS-aanvallen

Gepubliceerd op 14 min leestijd

Querypoort sluiten, anti-flood strakker zetten, rate limiting instellen: wat u op een TeamSpeak-3-server zelf kunt afschermen. En waar die maatregelen ophouden, omdat de lijn ervoor al vol zit.

Een TeamSpeak-server is voor een clan het zenuwcentrum. Wie hem uitschakelt, beëindigt niet alleen een gesprek, maar ook de training, de scrim of de raid. Precies daarom komen voiceservers vaak in het vizier, meestal van mensen uit de eigen omgeving: een verloren ronde, een ban, ruzie tussen twee clans.

Dit artikel laat zien wat u zonder extra kosten zelf kunt afschermen, waar die maatregelen tegen hun grens aanlopen en wat er daarna overblijft. De commando's zijn geschreven voor Debian 12, Debian 13, Ubuntu 22.04 LTS en Ubuntu 24.04 LTS. Waar root nodig is, staat dat erbij.

Waarom juist voiceservers zo vaak worden aangevallen

Drie nuchtere redenen, en geen ervan heeft met de omvang van uw project te maken.

Ten eerste is spraak in realtime genadeloos. Een website met twee procent pakketverlies valt niemand op, omdat TCP de ontbrekende segmenten gewoon opnieuw verstuurt. Bij spraak bestaat die herhaling niet: een verloren pakket is een gat in het geluid, en dat hoort iedereen aan tafel meteen. Een aanval hoeft uw lijn dus helemaal niet te verzadigen om hem onbruikbaar te maken.

Ten tweede is het spraakkanaal verbindingsloos. TeamSpeak verstuurt spraak via UDP. Er is geen handshake en geen toestand voordat het eerste pakket binnenkomt. Het afzenderadres laat zich vrij vervalsen, en uw server moet elk binnenkomend pakket eerst bekijken om het te kunnen weggooien. De aanvaller heeft geen toegang en geen wachtwoord nodig, alleen uw IP-adres en het poortnummer. Wat daarbij technisch gebeurt, legt het artikel Wat is een DDoS-aanval? uit.

Ten derde is precies dat adres openbaar. Het staat in de Discord, op de website en, als u dat aan hebt staan, in de TeamSpeak-serverlijst. Een voiceserver die niemand vindt, is nutteloos. Anonimiteit is daarom geen beschermingsstrategie.

De standaardpoorten van TeamSpeak 3

Voordat u ook maar iets gaat afschermen, moet u weten wat er eigenlijk openstaat. Dit zijn de fabrieksinstellingen van een TeamSpeak-3-server:

Poort Protocol Richting Functie
9987 UDP inkomend Spraakoverdracht (default_voice_port)
30033 TCP inkomend Bestandsoverdracht (avatars, icons, kanaalbestanden)
10011 TCP inkomend ServerQuery in platte tekst (raw)
10022 TCP inkomend ServerQuery via SSH
10080 en 10443 TCP inkomend ServerQuery via HTTP respectievelijk HTTPS
41144 TCP inkomend TSDNS, alleen nodig bij een eigen naamresolutie
2008 TCP uitgaand Licentie- en afrekendienst van TeamSpeak
2010 TCP uitgaand Vermelding in de openbare serverlijst

De belangrijkste regel uit deze tabel: vanaf het internet hoeft alleen 9987/UDP bereikbaar te zijn. Al het andere is optioneel of hoort achter een toegangsbeperking.

Wat u zelf kunt doen voordat u geld uitgeeft

De volgende tien stappen kosten niets en helpen tegen de aanvalssoorten die een voiceserver het vaakst raken: queryfloods, joinspam en kleinere UDP-floods uit een handvol bronnen.

1. Inventarisatie: wat luistert er werkelijk

Regels voor diensten die niet bestaan, zijn onschuldig. Eén over het hoofd geziene open poort kost u de avond. Verschaf uzelf daarom eerst als root een overzicht:

ss -lntup

Interessant is de kolom Local Address:Port. Staat daar 0.0.0.0:10011 of [::]:10011, dan is uw ServerQuery-toegang vanaf het hele internet bereikbaar. Staat er 127.0.0.1:10011, dan is hij alleen lokaal aanspreekbaar en heeft hij geen firewallregel meer nodig.

2. Alles sluiten wat niet nodig is

Een firewall met de standaardregel "al het inkomende verkeer weggooien" is de basis. Let daarbij op de volgorde, anders sluit u uzelf buiten. Het complete verloop inclusief vluchtweg beschrijft de handleiding UFW-firewall instellen zonder uzelf buiten te sluiten. Voor een TeamSpeak-server ziet het resultaat er zo uit:

ufw allow 22/tcp
ufw allow 9987/udp
ufw allow 30033/tcp
ufw default deny incoming
ufw default allow outgoing
ufw enable

Heeft u de ServerQuery-toegang werkelijk van buitenaf nodig, geef hem dan alleen vrij voor uw eigen adres. Vervang 203.0.113.10 door uw werkelijke IP-adres:

ufw allow from 203.0.113.10 to any port 10011 proto tcp

De uitgaande verbindingen mag u niet volledig dichtmetselen. Zonder toegang tot de licentie- en afrekendienst komt de TeamSpeak-server niet netjes op gang.

3. De ServerQuery-poort van het internet halen

De ServerQuery-toegang is het meest onderschatte aanvalsoppervlak van een TeamSpeak-server. Via poort 10011 kan iemand inloggegevens uitproberen en elke seconde nieuwe commando's afvuren. Dat is geen volumetrische aanval, maar juist een heel zuinige, en er komt geen botnet aan te pas.

Het netst is om de querydienst helemaal niet naar buiten te binden. Open de ts3server.ini in de servermap en zet daarin:

query_ip=127.0.0.1
query_protocols=raw
query_ip_allowlist=query_ip_allowlist.txt
query_ip_denylist=query_ip_denylist.txt
logquerycommands=1

Daarmee luistert de querydienst alleen nog op de server zelf en bereikt u hem indien nodig via een SSH-tunnel. Belangrijk is dat het bestand bij het starten ook werkelijk wordt ingelezen. De startparameter daarvoor luidt:

./ts3server_startscript.sh restart inifile=ts3server.ini

Het bestand query_ip_allowlist.txt bevat de adressen die van de floodcontrole van de querydienst zijn uitgezonderd, query_ip_denylist.txt de geblokkeerde. Vanaf serverversie 3.12 heten de bestanden zo, oudere versies gebruiken query_ip_whitelist.txt en query_ip_blacklist.txt. Zet in de allowlist alleen wat daar thuishoort, doorgaans 127.0.0.1. Elk extra adres is een uitzondering op precies de bescherming die u zojuist inschakelt.

4. De floodcontrole van de instantie strakker zetten

De server heeft een eigen rem voor ServerQuery aan boord. Log in als serveradmin zonder een virtuele server te kiezen en bekijk eerst de huidige waarden:

instanceinfo

Strakker zet u ze zo:

instanceedit serverinstance_serverquery_flood_commands=10 serverinstance_serverquery_flood_time=3 serverinstance_serverquery_ban_time=600

Dat staat tien commando's in drie seconden toe en blokkeert een adres daarna tien minuten lang. Toont uw serverversie in de uitvoer van instanceinfo daarnaast een bovengrens voor gelijktijdige queryverbindingen per adres, zet die dan eveneens op een kleine waarde.

5. Querybots nooit onder het serveradminaccount laten draaien

Ranksystem, muziekbot, statistiekscript: bijna elk daarvan draait met de volledige inloggegevens van serveradmin. Wordt zo'n bot gecompromitteerd of staat zijn wachtwoord in een openbaar configuratiebestand, dan is de server van iemand anders.

Maak in plaats daarvan een eigen querytoegang aan die aan een bepaalde clientidentiteit is gekoppeld, en geef die identiteit alleen de rechten die de bot nodig heeft:

queryloginadd client_login_name=ranksystem cldbid=42

De database-ID van uw bot vindt u via clientdblist. Het wachtwoord toont de server eenmalig, daarna niet meer.

6. Anti-flood van de virtuele server instellen

Naast de rem op instantieniveau heeft elke virtuele server een eigen puntensysteem tegen commandospam. Elk commando van een client kost punten, en per seconde worden er punten afgebouwd. Twee drempels leiden tot een reactie: de eerste blokkeert verdere commando's, de tweede blokkeert het adres. Kies de virtuele server en pas de waarden aan:

use sid=1
serveredit virtualserver_antiflood_points_tick_reduce=5 virtualserver_antiflood_points_needed_command_block=150 virtualserver_antiflood_points_needed_ip_block=250

Dit zijn de standaardwaarden. Bij aanhoudende join- en pokespam verlaagt u de beide drempels stapsgewijs en houdt u het logboek in de gaten. Te agressieve waarden raken uw eigen leden.

7. Identiteitsniveau verhogen tegen geautomatiseerde joinspam

Elke TeamSpeak-identiteit heeft een beveiligingsniveau dat door rekenwerk tot stand komt. De server kan een minimumniveau eisen, af fabriek is dat niveau 8. Wie massaal wegwerpidentiteiten wil aanmaken, moet voor elke afzonderlijke identiteit rekenen:

serveredit virtualserver_needed_identity_security_level=10

Dat werkt tegen botgolven, maar heeft een prijs: bestaande leden moeten hun identiteit eenmalig bijwerken, en vanaf ongeveer niveau 12 duurt dat op zwakkere apparaten onaangenaam lang. Kondig een verhoging aan in plaats van hem midden in de primetime door te voeren.

8. Serverlijst, serverwachtwoord en echte toegangsbeperking

De vermelding in de openbare serverlijst maakt uw adres machineleesbaar vindbaar en levert een gesloten clanserver niets op. Uitschakelen:

serveredit virtualserver_weblist_enabled=0

Wees daarbij eerlijk tegen uzelf: dit haalt een gemakkelijke manier weg om uw adres te vinden, maar verbergt het niet. Een scan over het adresbereik vindt een open UDP-poort 9987 toch wel.

Een echte toegangsbeperking bereikt u op twee manieren. Binnen TeamSpeak stelt u een serverwachtwoord in en werkt u met tokens voor de groepstoewijzing. Op netwerkniveau, een stuk harder, geeft u 9987/UDP alleen vrij voor bekende adressen of draait u de voiceserver binnen een VPN. Voor een vaste kring van tien mensen is dat werkbaar, voor een open community niet.

Wilt u een naam in plaats van een IP-adres verspreiden, gebruik dan een SRV-record van de vorm _ts3._udp.uw-domein.nl. De client lost dat inclusief poortnummer zelf op, en bij een wissel van IP-adres past u alleen die ene record aan.

9. Rate limiting op de host, met een eerlijke kanttekening

Op alle vier genoemde systemen werkt het pakketfilter onder de motorkap met nftables. Daarmee laat de pakketsnelheid per afzenderadres zich begrenzen. Maak daarvoor een eigen tabel aan, zodat u een bestaande UFW-configuratie niet hoeft aan te raken:

table inet ts3 {
    chain input {
        type filter hook input priority filter; policy accept;
        udp dport 9987 meter ts3flood { ip saddr limit rate over 400/second burst 800 packets } counter drop
    }
}

Sla dat op als /etc/nftables.d/ts3.nft, maak de map zo nodig eerst aan en laad het bestand als root:

nft -f /etc/nftables.d/ts3.nft
nft list table inet ts3

Ongedaan maken doet u met nft delete table inet ts3. Na een herstart is de tabel weg, tenzij het bestand vanuit /etc/nftables.conf wordt ingeladen.

Ter grootteorde: een sprekende client verstuurt bij frames van 20 milliseconden ongeveer 50 pakketten per seconde. 400 per seconde laat dus ruim voldoende lucht voor meerdere personen achter één aansluiting, en de teller laat zien of de regel eigenlijk wel heeft ingegrepen.

En dan nu de eerlijke kanttekening: tegen een gedistribueerde aanval helpt deze regel nauwelijks. Ze telt per afzenderadres, en een aanvaller vervalst het afzenderadres in elk pakket opnieuw. Ze is goed tegen afzonderlijke stoorzenders en tegen verkeerd geconfigureerde clients. Een DDoS-afweer is ze niet.

10. Loggen, zodat u in geval van nood cijfers heeft

Als het losbarst, heeft u meetwaarden nodig en niet het gevoel dat het hapert. De pakket- en fouttellers van de netwerkkaart leest u zo uit:

ip -s link show eth0

Twee keer uitgevoerd met tien seconden ertussen en dan het verschil genomen: dat is uw pakketsnelheid. Wie er op dat moment verbindingen met de voicepoort openhoudt, laat dit zien:

ss -uan 'sport = :9987'

Een kleine steekproef van het binnenkomende verkeer levert:

tcpdump -ni eth0 udp port 9987 -c 20

De logbestanden van de server staan in de submap logs/. Met logquerycommands=1 uit stap 3 staan daar ook de uitgevoerde querycommando's in, waardoor misbruik achteraf zichtbaar wordt. Waaraan u een aanval van een configuratiefout onderscheidt, laat het artikel DDoS-aanval op de server herkennen zien.

Waar deze maatregelen ophouden

Alle tien stappen hebben één ding gemeen: ze grijpen pas in als het pakket er al is. Bij kleine verstoringen volstaat dat prima, bij een volumetrische aanval niet, en wel om een reden die niets met uw configuratie te maken heeft.

Rekent u even mee: een aansluiting van 1 Gbit/s verplaatst ongeveer 125 megabyte per seconde en bij de kleinst mogelijke pakketten circa 1,49 miljoen pakketten per seconde. Bij 10 Gbit/s zijn dat navenant ongeveer 14,9 miljoen pakketten per seconde. Dat is de harde bovengrens van de lijn, ongeacht wat er op de server draait.

Een werkelijk gemeten aanval op een TeamSpeak-server op poort 9987 UDP kwam uit op ruim 473,4 Gbit/s en meer dan 41,5 miljoen pakketten per seconde. Dat is ongeveer 470 keer een aansluiting van 1 Gbit/s en nog altijd bijna het drievoudige van de pakketsnelheid die een aansluiting van 10 Gbit/s maximaal kan vervoeren.

Doorslaggevend is waar dat verkeer vastloopt: niet op uw netwerkkaart, maar op de lijn ervoor. Zit dat stuk weg vol, dan gaan de pakketten van uw leden daar al verloren, voordat uw server ze ooit te zien krijgt. Een firewallregel in het besturingssysteem kan geen lijn ontlasten die vóór het besturingssysteem eindigt.

Daar komt de rekentijd nog bij. Zelfs als uw kernel miljoenen pakketten per seconde zou kunnen weggooien, kost elk van die beslissingen CPU-tijd. Een voiceserver die druk bezig is met weggooien, klinkt net zo kapot als een server die helemaal niet meer antwoordt.

Wat KernelHost daar tegenover zet

Niveau 1: de inbegrepen permanente bescherming op elke server

Bij elke server van KernelHost draait de DDoS-filtering permanent mee, zonder meerprijs en zonder dat u iets hoeft in te schakelen of te configureren. Ze is in twee lagen opgebouwd:

  • Laag 1: 17 Tbps mitigatiecapaciteit in het wereldwijde scrubbing-netwerk. Volumetrische aanvallen worden dicht bij hun bron afgevangen, ruim voordat ze het datacenter bereiken. Precies die laag ontlast een lijn die u zelf niet kunt ontlasten.
  • Laag 2: 3,2 Tbps Arbor-realtimefiltering in het maincubes Premium Datacenter in Frankfurt am Main. Direct vóór de server worden protocolspecifieke patronen herkend en pakket voor pakket weggegooid, waaronder UDP-floods op de typische voice- en gameserverpoorten.

Twee punten zijn daarbij belangrijker dan ze klinken. Ten eerste is de bescherming permanent actief en hoeft ze niet eerst aan te slaan, er is dus geen aanloopfase waarin een aanval doorkomt. Ten tweede wordt er geen aangevallen IP-adres uit het netwerk gehaald: geen null-routing betekent dat uw leden gewoon doorpraten terwijl er gefilterd wordt. Hoe dat er voor andere titels en protocollen uitziet, beschrijft het artikel Gameserver-DDoS-bescherming in realtime.

Niveau 2: Advanced DDoS Protection voor permanent aangevallen projecten

Sommige projecten worden niet één keer geraakt, maar wekenlang. Voor die gevallen is er de Advanced DDoS Protection vanaf € 50,00 per maand, PrePaid en zonder minimale looptijd. Ze vult de inbegrepen permanente bescherming aan met drie dingen:

  • Een dedicated beschermd IP-adres uit de Frankfurtse kern, waarnaar uw server wordt omgezet. Aan uw kant is daarvoor geen verbouwing nodig.
  • Zelf beheerbare beschermingsregels per poort en protocol in het klantenpaneel. U stelt de filtering voor 9987/UDP anders in dan voor 30033/TCP, zonder een ticket te schrijven, en wijzigingen worden in realtime van kracht.
  • Een beschermingsprofiel dat past bij de betreffende game of dienst, met kant-en-klare profielen voor meer dan 40 games en protocollen, TeamSpeak inbegrepen.

PrePaid betekent hier precies dat: geen minimale looptijd, geen opzegtermijn, geen contract, geen installatiekosten. U neemt de bescherming erbij voor de duur van een aanvalsgolf en laat hem daarna aflopen.

De twee niveaus vergeleken

Kenmerk Inbegrepen permanente bescherming Advanced DDoS Protection
Prijs zonder meerprijs bij elke server inbegrepen vanaf € 50,00 per maand, PrePaid
Installatie geen, actief vanaf de eerste minuut bestelling in het klantenpaneel, dedicated beschermd IP-adres
Capaciteit 17 Tbps wereldwijde scrubbing plus 3,2 Tbps Arbor-realtimefiltering in Frankfurt am Main
Beschermingsregels automatische profielen, beheerd door het netwerkteam per poort en protocol zelf beheerbaar, wijzigingen worden in realtime van kracht
Gameprofiel automatisch toegewezen zelf te kiezen, meer dan 40 games en protocollen
Gedrag tijdens een aanval geen null-routing, het IP-adres blijft bereikbaar
Looptijd onderdeel van het serverpakket PrePaid, geen minimale looptijd, geen opzegtermijn
Geschikt voor de normale werking en incidentele aanvallen projecten die permanent en gericht onder vuur liggen

Veelgemaakte fouten en oplossingen

De voicepoort wordt gewijzigd zodat de aanval in het niets loopt: dat werkt precies zo lang tot iemand een poortscan laat lopen, dus meestal een paar minuten. Tegelijk moeten alle leden hun favorieten aanpassen. Een andere poort is alleen zinvol als u toch al meerdere instanties op één server draait.

ServerQuery blijft open omdat een bot het nodig heeft: die bot draait in de regel op dezelfde server, en dan volstaat query_ip=127.0.0.1. Draait hij ergens anders, geef de poort dan alleen vrij voor zijn vaste IP-adres en maak via queryloginadd een beperkte toegang voor hem aan.

De firewall wordt scherpgesteld en de toegang is weg: bij KVM-rootservers en dedicated servers van KernelHost komt u via de VNC-console in het klantenpaneel op het systeem. Die console hangt niet aan de netwerkstack van het gastsysteem, dus een firewallregel kan hem niet blokkeren. Log daar in als root en schakel de firewall met ufw disable uit voordat u de oorzaak gaat zoeken.

De rate limiting staat te strak en raakt de eigen leden: typisch is een studentenhuis of een gezin achter één gedeelde aansluiting. Voor het filter ziet dat eruit als één enkel adres met opvallend veel pakketten. Controleer de teller met nft list table inet ts3: loopt hij op terwijl er geen aanval bezig is, dan staat de waarde te laag.

De server start na de wijziging in de ts3server.ini niet meer: bijna altijd is het bestand wel bewerkt, maar bij het starten niet meegegeven, of andersom. Controleer allebei en kijk in het nieuwste bestand onder logs/, daar staat de oorzaak in duidelijke taal vermeld.

Alle maatregelen zijn doorgevoerd en de server is toch weg: dan is er sprake van een volumetrische aanval en heeft u op de server zelf niets meer in handen. Verzamel de waarden uit ip -s link en het tijdstip waarop het voor het eerst opviel, en geef beide door aan uw aanbieder. Bij KernelHost opent u een ticket in het klantenpaneel; bij een lopende aanval bereikt u ons daarnaast via de WhatsApp-noodchat op +43 650 8209883.

Snelle check voor het noodgeval

  1. Meten in plaats van gissen: ip -s link show eth0 twee keer uitvoeren en het verschil nemen.
  2. Controleren of alleen 9987/UDP en 30033/TCP openstaan, en de querypoort sluiten.
  3. De floodcontrole van de instantie en de anti-flood van de virtuele server nakijken.
  4. Zit de lijn zelf dicht: cijfers en tijdstip vastleggen en daarna de aanbieder inschakelen.

Veelgestelde vragen

Mijn TeamSpeak-server is op dit moment niet bereikbaar. Waaraan zie ik of het een aanval is?
Lees de tellers van de netwerkkaart met ip -s link show eth0 twee keer uit met tien seconden ertussen en neem het verschil. Loopt het aantal ontvangen pakketten ver boven de normale waarde uit terwijl er nauwelijks iemand verbonden is, dan wijst dat op een aanval. Blijft het onopvallend, dan ligt de oorzaak eerder bij de dienst zelf of bij het besturingssysteem.
Helpt het om de voicepoort van 9987 naar een andere poort te verplaatsen?
Nauwelijks. Een poortscan vindt de nieuwe poort meestal binnen een paar minuten, terwijl al uw leden hun favorieten moeten aanpassen. Als noodgreep levert het u hooguit een korte adempauze op, als bescherming deugt het niet.
Kan ik mij met nftables of iptables tegen een lopende aanval verweren?
Tegen afzonderlijke stoorzenders wel, tegen een gedistribueerde aanval niet. Rate limiting per afzenderadres grijpt niet als dat afzenderadres in elk pakket vervalst is. Bovendien werkt elke regel in het besturingssysteem pas als het pakket al binnen is. De lijn ervoor zit dan allang vol.
De ServerQuery-poort 10011 staat open. Kan iemand daarmee mijn server platleggen?
Ja, en daar heeft niemand een botnet voor nodig. Via de querypoort laten inloggegevens zich uitproberen en kunnen er elke seconde commando's worden afgevuurd. Bind de dienst met query_ip=127.0.0.1 in de ts3server.ini alleen lokaal en bereik hem via een SSH-tunnel. Heeft een bot hem van buitenaf nodig, geef de poort dan uitsluitend vrij voor zijn vaste IP-adres.
Heeft het zin om de server uit de openbare serverlijst te halen?
Het neemt aanvallers een gemakkelijke manier af om uw adres te vinden, maar verbergt het niet. Wie het adres al kent, houdt het, en een scan over het adresbereik vindt een open UDP-poort 9987 toch wel. De vermelding schakelt u via ServerQuery uit met serveredit virtualserver_weblist_enabled=0.
Haalt KernelHost mijn IP-adres tijdens een aanval uit het netwerk?
Nee. Er wordt geen null-routing ingezet. Het aangevallen IP-adres blijft bereikbaar, alleen de schadelijke pakketten worden weggegooid. De permanente bescherming is bij elke server continu actief en hoeft niet eerst aan te slaan, er is dus geen aanloopfase aan het begin van een aanval.
Volstaat de inbegrepen bescherming of heb ik de Advanced DDoS Protection nodig?
Voor de normale werking en incidentele aanvallen volstaat de inbegrepen permanente bescherming, die zonder meerprijs bij elke server zit: 17 Tbps mitigatiecapaciteit in het wereldwijde scrubbing-netwerk plus 3,2 Tbps Arbor-realtimefiltering in Frankfurt am Main. De Advanced DDoS Protection vanaf € 50,00 per maand loont als een project wekenlang gericht onder vuur ligt: een dedicated beschermd IP-adres en beschermingsregels die u per poort en protocol zelf in het klantenpaneel beheert. PrePaid, zonder minimale looptijd.
Ik word op dit moment aangevallen en ben nog geen klant. Wat doe ik nu?
Leg eerst meetwaarden vast: pakketsnelheid uit ip -s link, het getroffen IP-adres, de poort en het tijdstip waarop het voor het eerst opviel. Daarmee kan uw huidige aanbieder aan de slag. Filtert hij niet of haalt hij uw IP-adres offline, dan helpt op termijn alleen een verhuizing naar een omgeving met filtering in het netwerk. Bij een lopende aanval bereikt u ons via de WhatsApp-noodchat op +43 650 8209883.

TeamSpeak TeamSpeak-3-server DDoS-bescherming Voiceserver UDP-flood ServerQuery Anti-flood Gameserverbescherming