Protéger un serveur Rust contre les attaques DDoS

Publié le 17 min de lecture

Les serveurs Rust sont presque toujours attaqués au moment du wipe ou en plein raid. Ce que vous pouvez sécuriser vous-même, où la protection locale atteint ses limites physiques et ce qui doit se passer en amont dans le réseau.

Un serveur Rust tombe rarement par hasard. Le moment choisi trahit presque toujours le motif : l'attaque démarre à la minute du wipe, ou en plein raid. Quand vous êtes la cible, vous n'avez pas besoin d'un débat de principe, mais d'un ordre de marche. Cet article montre d'abord ce que vous pouvez changer sur le serveur lui-même, ensuite où ces possibilités s'arrêtent, et pour finir ce qui doit se passer en amont dans le réseau.

Pourquoi les serveurs Rust sont attaqués aussi souvent

Rust est un jeu dans lequel la progression est liée au temps. Un raid dure quelques minutes, un cycle de wipe plusieurs semaines. Une panne y vaut donc plus cher que dans presque tous les autres jeux : celui qui défend gagne du temps quand le serveur tombe. Celui qui attaque empêche l'adversaire de se connecter. Et celui qui exploite une communauté concurrente sait que la première soirée de wipe décide du nombre de joueurs pour tout le mois.

S'y ajoute un point qu'aucune configuration ne fait disparaître : un serveur Rust est publiquement identifiable par son adresse IP et son port, sinon personne ne pourrait le rejoindre. Contrairement à un site web placé derrière un proxy, un serveur de jeu doit publier sa véritable adresse. La question n'est donc jamais de savoir si l'attaquant trouve votre IP, mais uniquement ce qui se passe lorsqu'il tire dessus.

Les ports concernés

Dans sa configuration habituelle, un serveur Rust occupe quatre ports :

  • 28015/UDP, le port de jeu (server.port). C'est là que passe la totalité du trafic de jeu. UDP ne connaît pas d'établissement de connexion, chaque paquet se suffit à lui-même, et l'adresse d'expéditeur peut être falsifiée. Pour un attaquant, cela veut dire : aucune traçabilité, et malgré tout du travail pour votre serveur à chaque paquet.
  • Le port de requête (server.queryport), en UDP également. C'est par lui que le serveur répond aux requêtes Steam A2S_INFO, A2S_PLAYERS et A2S_RULES ; sans lui, il n'apparaît dans aucune liste de serveurs. Sans valeur explicite, il se place juste à côté du port de jeu, et beaucoup de lignes de démarrage le fixent sur 28017/UDP. Vérifiez dans votre propre ligne de démarrage plutôt que de vous fier à une valeur par défaut.
  • 28016/TCP, RCON (rcon.port), sous forme de variante WebSocket avec rcon.web 1.
  • 28082/TCP, l'application compagnon Rust+ (app.port).

Le port de requête est le plus désagréable des quatre, car une réponse A2S est nettement plus volumineuse que la requête. Un attaquant peut interroger des serveurs de jeu appartenant à d'autres avec une adresse d'expéditeur falsifiée et diriger les réponses vers sa véritable cible. Votre serveur n'est alors plus seulement une victime, il devient un amplificateur dirigé contre des tiers. Valve a pour cette raison ajouté une étape de challenge à A2S_INFO, ce qui a désamorcé le problème sans le supprimer. Les signes qui trahissent une attaque sont décrits dans l'article Détecter une attaque DDoS sur le serveur.

Ce que vous pouvez faire vous-même avant de dépenser de l'argent

La partie qui suit ne coûte rien et vaut la peine quel que soit l'endroit où votre serveur est hébergé. Elle ne vous débarrasse d'aucune attaque volumétrique, mais elle rend les petites attaques inopérantes et vous évite de deviner le jour où cela devient sérieux.

1. État des lieux : qu'est-ce qui écoute vraiment

Avant d'écrire la moindre règle, déterminez quels services sont joignables. Sur un serveur de jeu qui a grandi avec le temps, ils sont presque toujours plus nombreux que prévu :

ss -lntup

Tout ce qui est lié à 127.0.0.1 ou ::1 n'a besoin d'aucune ouverture dans le pare-feu. Tout ce qui écoute sur 0.0.0.0 ou [::] est joignable depuis Internet, y compris le service de base de données qu'un plugin a installé au passage. Comparez la sortie avec votre ligne de démarrage :

./RustDedicated -batchmode -nographics \
  +server.port 28015 \
  +server.queryport 28017 \
  +server.identity "wipe" \
  +server.maxplayers 150 \
  +rcon.port 28016 \
  +rcon.web 1 \
  +rcon.password "VOTRE-LONG-MOT-DE-PASSE-ALEATOIRE"

Si votre Rust a été installé via SteamCMD, l'article Installer un serveur de jeu avec SteamCMD couvre la couche située en dessous.

2. Ne laisser ouverts que les ports dont Rust a réellement besoin

Quatre ports, pas un de plus. RCON n'a rien à faire en accès libre sur Internet, il doit être restreint à votre adresse, et Rust+ ne s'ouvre que si vous utilisez effectivement l'application compagnon :

ufw allow 28015/udp comment "Rust port de jeu"
ufw allow 28017/udp comment "Rust Query"
ufw allow from 203.0.113.10 to any port 28016 proto tcp comment "Rust RCON"
ufw allow 28082/tcp comment "Rust Companion"

Remplacez 203.0.113.10 par votre propre adresse. Si votre adresse change régulièrement, la solution passe par un tunnel SSH.

Un avertissement qui coûte des serveurs chaque année : l'ordre dans lequel vous activez un pare-feu décide si vous vous coupez vous-même l'accès. Cet ordre, voie de retour comprise, figure dans l'article Configurer le pare-feu UFW. Si cela arrive quand même : sur les serveurs root KVM et les serveurs dédiés de KernelHost, vous atteignez la machine par la console VNC de l'espace client. Elle ne dépend pas de la pile réseau du système invité et aucune règle de pare-feu à l'intérieur de l'invité ne peut la bloquer.

3. Sécuriser le port de requête sans disparaître de la liste des serveurs

Le réflexe évident, bloquer le port de requête, est l'erreur la plus coûteuse de tout ce domaine. Sans lui, votre serveur disparaît du navigateur de serveurs, affiche de faux nombres de joueurs et est signalé hors ligne par les sites de listage. Vous auriez achevé l'attaque vous-même.

La bonne réponse est une limitation de débit par adresse source. Un vrai client qui parcourt la liste envoie quelques requêtes par seconde, un outil d'amplification en envoie des milliers. Avec nftables, dans une table à part qui est évaluée avant la chaîne de filtrage :

table inet rust {
    chain input {
        type filter hook input priority -10; policy accept;
        udp dport 28017 meter rustquery { ip saddr limit rate over 15/second } drop
    }
}

Vous chargez le fichier avec nft -f. La priorité -10 fait en sorte que la règle s'applique avant la chaîne de filtrage qu'UFW crée avec la priorité 0. Avec l'iptables classique, le module hashlimit obtient le même résultat :

iptables -A INPUT -p udp --dport 28017 -m hashlimit \
  --hashlimit-name rustquery --hashlimit-mode srcip \
  --hashlimit-above 15/sec --hashlimit-burst 30 -j DROP

Commencez large et ne resserrez la limite qu'une fois que vous avez la preuve que les requêtes légitimes passent. Sinon, une limite trop stricte ne se remarque que le jour du wipe.

4. Soulager le suivi de connexions

Ce point passe presque toujours inaperçu et explique des pannes qui ressemblent à une attaque volumétrique sans en être une. Pour le trafic UDP, le noyau crée des entrées dans le suivi de connexions (conntrack), et avec des adresses d'expéditeur falsifiées, chaque nouvelle adresse signifie une entrée de plus. Une fois la table pleine, le noyau rejette les paquets sans faire de différence : l'attaque et vos joueurs sortent ensemble. Le journal système affiche alors nf_conntrack: table full, dropping packet. Vous pouvez le vérifier ainsi :

sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max
dmesg | grep -i conntrack

L'étape la plus efficace consiste à ne pas soumettre du tout le trafic de jeu au suivi de connexions. Rust n'a besoin d'aucun suivi d'état dans le noyau pour cela, il gère ses sessions lui-même :

table inet raw {
    chain prerouting {
        type filter hook prerouting priority raw; policy accept;
        udp dport 28015 notrack
    }
}

Avec iptables, l'équivalent est :

iptables -t raw -A PREROUTING -p udp --dport 28015 -j NOTRACK

Ce n'est qu'ensuite qu'il vaut la peine d'augmenter nf_conntrack_max. Agrandir la table d'abord ne repousse le problème que de quelques minutes et consomme de la RAM pour cela.

5. Tampons de réception et paramètres du noyau

Si les paquets arrivent plus vite que le processus Rust ne les récupère, le tampon de réception du socket déborde. Pour les joueurs, cela ressemble à de la perte de paquets, alors que la liaison est libre :

net.core.rmem_max = 16777216
net.core.rmem_default = 1048576
net.core.netdev_max_backlog = 16384

Déposez ces valeurs sous /etc/sysctl.d/ et activez-les avec sysctl -p. Le noyau vous dit lui-même si elles sont nécessaires : si UdpRcvbufErrors augmente dans nstat -az, ou si ss -lunp montre en permanence quelque chose dans la file de réception, alors elles servent à quelque chose. Si les deux restent à zéro, l'ajustement ne change rien. C'est de la réserve, pas une protection.

6. Sécuriser RCON

Un port RCON ouvert avec un mot de passe faible n'est pas un problème de DDoS, c'est une prise de contrôle : celui qui dispose de RCON peut bannir, débannir et arrêter le jeu. Ne laissez jamais rcon.password vide et ne choisissez jamais une valeur devinable, une valeur issue de openssl rand -base64 32 se génère en cinq secondes. Et n'ouvrez pas ce port publiquement, restreignez-le à votre adresse.

7. Mesures du côté de l'anti-cheat et des plugins

Beaucoup des pannes que les exploitants signalent comme des attaques DDoS n'en sont pas. Ce sont des plantages qu'un seul client déclenche avec quelques centaines de paquets, parce qu'une faille reste ouverte dans le binaire du serveur ou dans un plugin. Contre cela, c'est l'entretien qui aide, pas la bande passante :

  • Gardez le binaire du serveur à jour. La mise à jour mensuelle qui impose le wipe est en même temps une mise à jour de sécurité. La repousser, c'est rester avec les bugs connus.
  • Gardez le framework de plugins à jour. Oxide/uMod et Carbon suivent après chaque mise à jour de Rust. Un framework qui ne correspond pas à la version du serveur est la cause la plus fréquente de plantages le soir du wipe.
  • Moins de plugins. Chaque plugin est du code supplémentaire dans le même processus. Les plugins qui embarquent leurs propres services web (vues de carte, pages de statistiques) ouvrent d'autres ports et publient souvent, au passage, exactement l'adresse que vous cherchez à protéger.
  • Entretenez vos listes de bannissement. Les tentatives de connexion répétées depuis le même compte se bloquent avec les moyens du bord. Rust enregistre les propriétaires et les modérateurs dans server/<identity>/cfg/users.cfg, et les bannissements dans server/<identity>/cfg/bans.cfg. Un bannissement posé via banid survit au redémarrage.

Rust n'intègre pas de liste blanche dans son cœur, elle arrive par le framework de plugins. Sur un serveur privé ou communautaire, elle est efficace. Sur un serveur de wipe public, ce n'est pas une option : un serveur où personne ne peut entrer est aussi vide qu'un serveur hors ligne.

8. La liste des serveurs et votre propre adresse

L'adresse IP publique du serveur de jeu ne peut pas être changée, mais tout ce qui l'entoure, si. Un attaquant trouve souvent l'environnement complet du même coup : le serveur web avec la boutique, la machine du bot Discord, le serveur de sauvegarde, l'accès au panneau de contrôle. Ces adresses n'ont leur place ni dans la même annonce ni dans de vieilles entrées DNS. Vérifiez une fois par trimestre quel sous-domaine pointe où.

9. Journaliser pour ne pas deviner pendant l'attaque

Pendant une attaque, une seule question compte : combien arrive, et sur quel port. Trois commandes suffisent :

ip -s link show eth0
nstat -az | grep -i udp
journalctl -u rust-server -f

La première commande affiche les paquets, les erreurs et les rejets par interface. Lancez-la deux fois à dix secondes d'intervalle et vous obtenez un débit au lieu d'une valeur absolue. Chez vous, l'interface et l'unité de service portent peut-être un autre nom, vérifiez les deux avec ip -br link et systemctl list-units --type=service. Un échantillon vous montre à quoi ressemblent les paquets, et il doit rester court, car une capture sous charge consomme du temps de calcul :

tcpdump -ni eth0 -c 200 "udp port 28015"

Là où la protection locale s'arrête

Passons à la partie honnête. Tout ce qui précède n'agit qu'une fois les paquets arrivés sur votre carte réseau. Un serveur est en général raccordé à 1 Gbit/s ou 10 Gbit/s. Avec la plus petite taille de paquet possible, une liaison à 1 Gbit/s transporte environ 1,49 million de paquets par seconde, une liaison à 10 Gbit/s environ 14,88 millions. C'est la limite physique, indépendamment du CPU, du noyau et du pare-feu.

Face à cela, il y a les attaques réelles. Deux exemples tirés de l'exploitation chez KernelHost, tous deux filtrés en temps réel : un flood UDP contre un serveur de jeu ARK sur le port 7777/UDP, avec plus de 112,2 Gbit/s et plus de 8,7 millions de paquets par seconde, ainsi qu'une attaque multivecteur contre un serveur vocal sur le port 9987/UDP, avec plus de 473,4 Gbit/s et plus de 41,5 millions de paquets par seconde.

Rapportez cela à votre propre liaison : 473,4 Gbit/s représentent environ 470 fois un raccordement à 1 Gbit/s, et encore environ 47 fois un raccordement à 10 Gbit/s. Votre règle a beau être parfaitement correcte, elle ne sera jamais exécutée, car la perte se produit sur le routeur situé en amont. Et bien avant que la liaison ne soit saturée, le CPU est au bout : chaque paquet coûte une interruption et un passage dans la pile réseau, même s'il est rejeté ensuite.

C'est pourquoi les deux freins d'urgence habituels sont l'un comme l'autre insatisfaisants. Le null-routing (blackholing) retire du réseau l'IP attaquée et met bien fin à l'attaque, mais aussi à votre serveur. Et une redirection réactive vers un système de filtrage consomme, pendant son temps de bascule, exactement les minutes qui décident du raid. Seul un filtrage permanent, qui tourne dans le réseau en amont du serveur, est réellement efficace.

Ce que KernelHost place en amont

La protection permanente qui tourne sur chaque serveur

La protection DDoS de KernelHost est construite sur deux niveaux et reste active en permanence, sans que vous ayez quoi que ce soit à activer. Le premier niveau est un réseau de scrubbing mondial doté de 17 Tbps de capacité de mitigation, qui intercepte les attaques volumétriques au plus près de leur source, avant qu'elles n'atteignent le centre de données. Le second niveau est un filtrage Arbor en temps réel de 3,2 Tbps directement sur place, à Francfort-sur-le-Main, qui assure le travail de précision au niveau des protocoles et rejette les schémas complexes sur les couches 3 à 7.

Deux points sont décisifs. Premièrement, le filtrage tourne en permanence : il n'y a donc aucun délai de détection ni de bascule pendant lequel vos joueurs se feraient éjecter. Deuxièmement, aucun null-routing n'est utilisé : l'IP attaquée reste dans le réseau, seuls les paquets nuisibles disparaissent. La protection est comprise sans supplément dans chaque pack serveur, sans pack de protection séparé et sans mise en service. Les serveurs se trouvent dans le maincubes Premium Datacenter de Francfort-sur-le-Main (Allemagne), certifié TÜV TIER3+ et raccordé directement au DE-CIX. L'exploitant est KernelHost GmbH, dont le siège se trouve à Vienne (Autriche). Les jeux et protocoles couverts sont listés dans l'article Protection DDoS des serveurs de jeu en temps réel.

Advanced DDoS Protection pour les projets attaqués en continu

Certains projets Rust ne sont pas touchés de temps en temps : ils sont visés pendant des semaines, avec des schémas changeants et toujours pile au moment du wipe. Pour ces cas, il existe l'Advanced DDoS Protection à partir de 50,00 € par mois, en PrePaid et sans durée minimale. Elle apporte trois choses que la protection permanente incluse n'offre pas sous cette forme :

  • Une IP protégée dédiée. Votre serveur y est basculé au sein de notre propre réseau, aucune modification n'est nécessaire de votre côté.
  • Des règles de protection que vous gérez vous-même, par port et par protocole. Vous décidez dans l'espace client quel port est filtré avec quel profil, par exemple 28015/UDP autrement que le port de requête. Les changements s'appliquent en temps réel, sans ticket et sans attente.
  • Un profil de protection adapté au jeu concerné. Pour Rust comme pour plus de 40 autres jeux, services et protocoles, plus des profils TCP et UDP librement affectables pour les serveurs modifiés.

Ici aussi, c'est le modèle PrePaid qui s'applique : pas de durée minimale, pas de préavis de résiliation, pas de contrat et pas de frais de mise en service. Une fois la vague d'attaques passée, vous ne renouvelez tout simplement pas.

Les deux niveaux comparés

Caractéristique Protection permanente incluse Advanced DDoS Protection
Prix Comprise dans chaque pack serveur, sans supplément à partir de 50,00 € par mois, en PrePaid sans durée minimale
Activation Active dès la première minute, rien à configurer Commander, recevoir l'IP protégée, le serveur est basculé
Adresse IP IP du serveur issue du réseau de Francfort IP protégée dédiée supplémentaire
Filtrage 17 Tbps de scrubbing mondial, plus 3,2 Tbps de filtrage Arbor en temps réel à Francfort-sur-le-Main Le même filtrage, plus vos propres règles par port et par protocole
Modifier les règles Entretenues par KernelHost, réglage fin par ticket Vous-même dans l'espace client, effectives en temps réel
Profils de jeu Plus de 40 jeux et protocoles Profil sélectionnable par port, y compris pour les serveurs modifiés
Null-routing pendant l'attaque Non Non
Convient à Chaque serveur, dès le premier wipe Les projets attaqués de manière ciblée et durable

Erreurs fréquentes et solutions

Le serveur a disparu du navigateur de serveurs mais continue de tourner : le port de requête est presque toujours bloqué ou limité trop strictement. Vérifiez avec ss -lunp qu'il écoute et desserrez la limite de débit par étapes. Si Rust+ reste muet, c'est en général app.port qui est fermé.

Tous les joueurs ont un ping élevé et du rubberbanding, mais la liaison n'est pas saturée : cela indique un problème de débit de paquets et non de volume. Regardez les paquets rejetés dans ip -s link show et les compteurs UDP dans nstat -az. Un tampon de réception plein ou un suivi de connexions épuisé produit exactement cette image.

La règle de pare-feu est correcte et reste pourtant sans effet : c'est que la liaison en amont du serveur est saturée. Une règle qui n'est jamais exécutée, parce que le paquet est déjà tombé sur le routeur situé devant, ne peut rien changer. À partir de ce point, seul un filtrage dans le réseau aide.

Plus aucun accès SSH après l'activation du pare-feu : connectez-vous par la console VNC de l'espace client. Elle permet de désactiver le pare-feu et d'ajouter la règle manquante, même lorsque plus rien ne passe par le réseau.

L'attaque s'interrompt après un changement d'IP et revient au bout d'un ou deux jours : c'est le cas normal. Votre serveur publie lui-même la nouvelle adresse dans la liste des serveurs dès qu'il est de nouveau en ligne. Un changement d'IP fait gagner quelques heures, ce n'est pas une solution.

Des commandes d'administration que vous n'avez pas lancées s'exécutent sur le serveur : ce n'est pas du DDoS, c'est un accès RCON compromis. Changez le mot de passe immédiatement, restreignez le port à votre adresse, contrôlez la liste de bannissement.

Si vous êtes attaqué en ce moment

Si votre serveur tourne déjà chez KernelHost, le filtrage est actif en permanence et vous n'avez rien à activer. Si vous constatez malgré tout des anomalies, ouvrez un ticket de support pour que notre équipe réajuste les règles de filtrage pour votre IP. Pendant une attaque en cours, vous pouvez également nous joindre par le chat d'urgence WhatsApp au +43 650 8209883.

Indiquez d'emblée quatre éléments : l'adresse IP, le port, la période dans votre fuseau horaire et, en une phrase, ce que vous observez (joueurs éjectés, serveur injoignable, ping élevé). Cela évite un aller-retour de questions, et ce temps compte quand le wipe est lancé.

Questions fréquentes

Mon serveur Rust est injoignable en ce moment : est-ce une attaque ?
Regardez d'abord l'interface réseau. Si les paquets rejetés dans "ip -s link show" et les erreurs UDP dans "nstat -az" grimpent fortement alors que le CPU du processus Rust reste normal, cela plaide pour une attaque. Si les deux valeurs restent calmes et que le processus a disparu, c'était un plantage.
Quels ports un serveur Rust doit-il avoir ouverts ?
28015/UDP pour le trafic de jeu, le port de requête (server.queryport, souvent 28017/UDP) pour la liste des serveurs, 28016/TCP pour RCON et 28082/TCP uniquement si vous utilisez l'application compagnon Rust+. RCON doit être restreint à votre propre adresse IP, tout le reste demeure fermé.
Est-ce utile de simplement bloquer le port de requête ?
Non, cela nuit. Sans port de requête joignable, votre serveur disparaît du navigateur de serveurs et les sites de listage le signalent hors ligne. Ce qui fonctionne, c'est une limitation de débit par adresse source, par exemple avec un meter nftables ou avec le module iptables hashlimit.
Un changement d'IP aide-t-il contre une attaque en cours ?
Seulement pour un court moment. Votre serveur republie lui-même la nouvelle adresse dans la liste des serveurs dès qu'il est en ligne. Dans la pratique, l'attaque revient au bout d'un ou deux jours. Un changement d'IP fait gagner quelques heures, il ne résout rien.
Puis-je me protéger avec un pare-feu sur le serveur lui-même ?
Contre les petites attaques oui, contre les attaques volumétriques non. Vos règles ne s'exécutent qu'une fois les paquets arrivés sur la carte réseau. Une liaison à 1 Gbit/s transporte environ 1,49 million de petits paquets par seconde, et les attaques réelles se situent bien au-delà. La perte se produit alors déjà sur le routeur situé en amont.
KernelHost met-il mon IP hors ligne pendant une attaque ?
Non. Ni null-routing ni blackholing ne sont utilisés. L'IP attaquée reste dans le réseau, seuls les paquets nuisibles disparaissent. Le filtrage tourne en permanence, il n'y a donc pas non plus de temps de bascule au début d'une attaque.
Que comprend la protection DDoS et combien coûte le niveau Advanced ?
La protection permanente à deux niveaux est comprise sans supplément dans chaque pack serveur : 17 Tbps de capacité de mitigation dans le réseau de scrubbing mondial, plus 3,2 Tbps de filtrage Arbor en temps réel à Francfort-sur-le-Main. L'Advanced DDoS Protection, avec IP protégée dédiée et règles propres par port, coûte à partir de 50,00 € par mois, en PrePaid, sans durée minimale et sans frais de mise en service.
Que dois-je écrire dans le ticket quand l'attaque est en cours ?
Quatre éléments suffisent pour commencer : l'adresse IP concernée, le port, la période dans votre fuseau horaire et, en une phrase, ce que vous observez. Cela permet de réajuster les règles de filtrage pour votre IP sans aller-retour de questions. En cas d'urgence, vous pouvez également nous joindre par le chat d'urgence WhatsApp au +43 650 8209883.

Serveur Rust Protection DDoS Rust Protection serveur de jeu Flood UDP Port de requête nftables Advanced DDoS Protection Wipe