Dlaczego Twoje Dedicated Servers zamarzają: Rzeczywistość DDoS Protection w serwerach Unreal Engine
Każdy deweloper gier Multiplayer boi się nagłego, niewyjaśnionego zamrożenia serwera. Twoja instancja dedykowana działa bez zarzutu przy stabilnym Tick rate wynoszącym 30, a potem, bez ostrzeżenia, cała symulacja zatrzymuje się w miejscu. Gracze doświadczają Rubber-banding na mapie, RPCs wypadają, a chwilę później fatalny Connection timeout kończy mecz. Możesz instynktownie obwiniać swój najnowszy kod Movement replication lub złożone obliczenia fizyki, ale jeśli baza graczy rośnie, rzeczywistość często jest znacznie bardziej złośliwa: Twoja infrastruktura jest ofiarą skoordynowanego ataku Distributed Denial of Service (DDoS).
Ostatnie raporty społeczności deweloperów Unreal Engine wskazują na ogromny wzrost zorganizowanych ataków DDoS wymierzonych w serwery gier, szczególnie dotykających tryby o dużej skali, takie jak Battle Royale czy niestandardowe instancje Creative. Ataki te całkowicie przeciążają Network processing thread serwera, co skutkuje poważnym Lag, globalną desynchronizacją i ostatecznie Hard crashes.
Dla deweloperów Indie i studiów AA wdrożenie solidnej ochrony Unreal Engine Server DDoS Protection nie jest już opcjonalne — to obowiązkowy wymóg dla każdej gry Live-ops. W tej analizie technicznej sprawdzimy, jak te ataki manipulują Netcode silnika Unreal Engine, jak odróżnić złośliwy Flood od standardowych złych warunków sieciowych oraz jakie konkretne kroki możesz podjąć, aby wzmocnić infrastrukturę swojej gry.
Anatomia crashu serwera Unreal Engine
Aby zrozumieć, jak chronić serwer, musisz najpierw zrozumieć, jak Unreal Engine przetwarza przychodzący ruch sieciowy. Unreal wykorzystuje niestandardowy protokół oparty na UDP, zarządzany przez NetDriver. Ponieważ UDP jest bezpołączeniowe, każdy klient w internecie może wysyłać pakiety na otwarty port Twojego serwera bez formalnego Handshake.
Ataki wolumetryczne w warstwie 4 vs ataki aplikacyjne w warstwie 7
Większość awarii serwerów jest spowodowana jednym z dwóch rodzajów ataków sieciowych:
1. Wolumetryczne Floody UDP (Warstwa 4): Jest to atak typu brute-force. Botnet bombarduje publiczny adres IP i port Twojego serwera gigabajtami śmieciowych pakietów UDP na sekundę. Karta sieciowa (NIC) serwera i Network stack systemu operacyjnego zostają całkowicie nasycone. Zanim Unreal Engine w ogóle zdąży przyjrzeć się pakietom, maszynie kończy się Bandwidth lub przerwania procesora (CPU interrupts) uniemożliwiają obsługę legalnego ruchu graczy.
2. Wyczerpanie warstwy aplikacyjnej (Warstwa 7):
Ataki te są znacznie bardziej podstępne. Zamiast wysyłać losowe śmieci, atakujący używa narzędzi Packet capture lub zmodyfikowanych klientów gry, aby wysyłać poprawnie sformatowane żądania połączenia Unreal Engine (takie jak pakiety NMT_Hello lub NMT_Login) lub specyficzny ciężki spam RPC. NetDriver akceptuje te pozornie prawidłowe pakiety i przekazuje je do Game thread w celu przetworzenia. Obciążenie CPU serwera skacze do 100%, gdy próbuje on przetworzyć tysiące fałszywych Handshakes logowania, zweryfikować nieistniejące bilety sesji lub przydzielić pamięć dla złożonych parametrów ciągów znaków w replikowanych funkcjach. Ponieważ dla standardowego Firewalla ruch ten wygląda identycznie jak legalna aktywność graczy, omija on podstawową ochronę DDoS. To natychmiast niszczy Tick rate serwera, powodując ekstremalne teleportowanie i zachowania typu Rollback, których gracze doświadczają tuż przed tym, jak proces Watchdog zabije zamrożoną instancję.
Diagnozowanie ataku: czy to atak, czy tylko zły Netcode?
Zanim założysz, że Twój serwer jest atakowany, musisz wykluczyć katastrofalne błędy Replication. Jeśli pojedynczy klient wyzwala nieskończoną pętlę wywołań RPC, może to naśladować DDoS w warstwie 7. Przejrzyj logi i metryki. Jeśli widzisz ogromne skoki w Memory allocation przy niskim ruchu sieciowym, możesz mieć do czynienia z problemem z Replication — po wskazówki zapraszamy do naszego przewodnika Zero Ping Spikes Complete Freeze The Ultimate Uefn Server Crash Fix Protocol.
Jeśli jednak Twój zewnętrzny monitoring pokazuje skok ruchu przychodzącego z poziomu ~50 Mbps do 5 Gbps lub jeśli logi serwera pokazują tysiące komunikatów LogNet: NotifyAcceptingConnection z unikalnych adresów IP w ciągu kilku sekund, masz do czynienia ze skoordynowanym atakiem.
Wzmacnianie Netcode: Wdrażanie Connection Throttling w C++
Podczas gdy prawdziwa mitygacja wolumetrycznych ataków DDoS musi odbywać się na poziomie infrastruktury (co omówimy za chwilę), możesz chronić swój serwer Unreal Engine przed wyczerpaniem warstwy 7, wdrażając agresywny Rate Limiting bezpośrednio w AGameModeBase.
Nadpisując funkcję PreLogin, możesz przechwytywać próby połączenia, zanim serwer przydzieli pełny APlayerController i rozpocznie kosztowny proces ładowania gracza do świata.
Hier is a robust C++ implementation to throttle rapid connection attempts from malicious IP addresses:
// In YourGameMode.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "YourGameMode.generated.h"
UCLASS()
class YOURGAME_API AYourGameMode : public AGameModeBase
{
GENERATED_BODY()
public:
virtual void PreLogin(const FString& Options, const FString& Address, const FUniqueNetIdRepl& UniqueId, FString& ErrorMessage) override;
private:
// Maps to track connection attempts per IP
TMap<FString, int32> ConnectionAttempts;
TMap<FString, float> LastConnectionTime;
// Configuration limits
const int32 MaxAttemptsPerMinute = 4;
const float LockoutTimeSeconds = 60.0f;
};
// In YourGameMode.cpp
#include "YourGameMode.h"
#include "Engine/World.h"
void AYourGameMode::PreLogin(const FString& Options, const FString& Address, const FUniqueNetIdRepl& UniqueId, FString& ErrorMessage)
{
// Always call super first to handle native bans and base logic
Super::PreLogin(Options, Address, UniqueId, ErrorMessage);
// If an error was already generated (e.g., server full), exit early
if (!ErrorMessage.IsEmpty())
{ return;
}
// The Address string usually arrives in the format "IP:Port"
FString ClientIP;
FString PortStr;
if (!Address.Split(TEXT(":"), &ClientIP, &PortStr))
{ ClientIP = Address; // Fallback if no port is appended
}
float CurrentTime = GetWorld()->GetTimeSeconds();
// Check if this IP is currently in our tracking map
if (LastConnectionTime.Contains(ClientIP))
{ float TimeSinceLastAttempt = CurrentTime - LastConnectionTime[ClientIP];
// If they are connecting too fast and have exceeded the attempt limit
if (TimeSinceLastAttempt < LockoutTimeSeconds && ConnectionAttempts[ClientIP] >= MaxAttemptsPerMinute)
{ ErrorMessage = TEXT("Connection rate limit exceeded. Please wait 60 seconds.");
UE_LOG(LogGameMode, Warning, TEXT("DDoS Mitigation: Rejected rapid connection attempt from %s."), *ClientIP);
return;
}
// If the lockout window has passed, reset their counter
if (TimeSinceLastAttempt >= LockoutTimeSeconds)
{ ConnectionAttempts[ClientIP] = 0;
} }
// Increment the attempt counter and update the timestamp
int32 Attempts = ConnectionAttempts.FindOrAdd(ClientIP, 0);
ConnectionAttempts[ClientIP] = Attempts + 1;
LastConnectionTime.Add(ClientIP, CurrentTime);
UE_LOG(LogGameMode, Log, TEXT("Connection validation passed. Attempt %d from %s"), ConnectionAttempts[ClientIP], *ClientIP);
}
Dlaczego ten kod ma znaczenie
Ta implementacja śledzi adres IP każdego przychodzącego żądania. Jeśli pojedynczy adres IP próbuje połączyć się więcej niż 4 razy w ciągu 60 sekund, serwer aktywnie odrzuca połączenie w PreLogin. Odrzucenie połączenia w tym miejscu jest znacznie tańsze dla procesora niż pozwolenie silnikowi na stworzenie aktora, zreplikowanie stanów początkowych, a następnie wyrzucenie gracza. Ten prosty blok kodu może zadecydować o tym, czy Twój serwer przetrwa atak typu script-kiddie w warstwie 7, czy całkowicie przestanie odpowiadać.
Tuning konfiguracji sieciowej Unreal Engine
Poza logiką C++, plik DefaultEngine.ini zawiera kilka krytycznych parametrów. Pozostawienie ich na ustawieniach domyślnych to ogromna luka w zabezpieczeniach. Jeśli atakujący zalewa serwer, a limity przepustowości nie są ustawione, serwer spróbuje przetworzyć wszystko, co natychmiast maksymalnie obciąży CPU.
Musisz ustanowić ścisłe górne granice ruchu sieciowego. Otwórz DefaultEngine.ini i zastosuj te limity dla IpNetDriver:
[/Script/Engine.Player]
; Limit maximum connection speed to 10 MB/s to prevent single-client bandwidth exhaustion
ConfiguredInternetSpeed=10485760
ConfiguredLanSpeed=10485760
[/Script/OnlineSubsystemUtils.IpNetDriver]
; Maximum data rate allowed per client (in bytes). 100kb/s is usually plenty for an FPS.
MaxClientRate=100000
MaxInternetClientRate=100000
; Cap the server tick rate to ensure predictable CPU load.
NetServerMaxTickRate=30
; Aggressively drop unresponsive clients. Defaults are often too long (60s+).
ConnectionTimeout=15.0
InitialConnectTimeout=15.0
; How often the server expects a keep-alive ping.
KeepAliveTime=0.2
; Limit the number of ports the server will try to bind to upon startup.
MaxPortCountToTry=512
Zmniejszając ConnectionTimeout do 15.0 sekund, Twój serwer będzie szybko usuwał półotwarte lub martwe połączenia wygenerowane przez atak DDoS, zwalniając pamięć i sloty sieciowe dla prawdziwych graczy.
Problem z infrastrukturą: Nie możesz zablokować tego, co już dotarło
Ograniczanie połączeń w C++ i konfiguracje INI ochronią Cię przed wyczerpaniem warstwy aplikacyjnej, ale mają fatalną wadę w przypadku wolumetrycznych ataków w warstwie 4: zanim Twój serwer Unreal Engine zdecyduje o odrzuceniu pakietu, przepustowość (Bandwidth) została już zużyta.
Jeśli atakujący skieruje na Twój serwer Botnet o przepustowości 10 Gbps, a Twój dostawca hostingu zapewnia tylko interfejs sieciowy 1 Gbps, nie ma znaczenia, jak zoptymalizowany jest Twój kod C++. Rury prowadzące do Twojego serwera są fizycznie zatkane. Legalny ruch graczy nie może się przebić.
Mitygacja ataków w warstwie 4 wymaga strategii obronnej na poziomie infrastruktury.
Podejście DIY
Jeśli prowadzisz własne serwery dedykowane Bare-metal lub standardowe instancje EC2, musisz ręcznie zbudować potok mitygacji. Zazwyczaj obejmuje to:
- Konfigurację Reverse Proxy: Nie możesz ujawniać publicznie rzeczywistego adresu IP serwera Unreal Engine. Musisz kierować ruch przez proxy UDP (np. NGINX skonfigurowany z modułem
streamlub HAProxy). Dodaje to opóźnienie, ale pozwala ukryć prawdziwy adres IP instancji. - Konfigurację iptables/nftables: Musisz napisać ścisłe reguły Firewalla, aby odrzucać pofragmentowane pakiety UDP i ograniczać połączenia na adres IP na poziomie jądra.
- Zakup mitygacji klasy Enterprise: Musisz wykupić drogie usługi routingu (takie jak AWS Shield Advanced lub Cloudflare Magic Transit), aby odfiltrować złośliwy ruch, zanim trafi on do Twojego centrum danych.
Samodzielne zbudowanie tej architektury wymaga skonfigurowania menedżerów floty, Load balancers i złożonych tablic routingu — to co najmniej 4-6 miesięcy specjalistycznej pracy DevOps. To ogromne obciążenie finansowe i czasowe dla studia Indie.
Ucieczka z pułapki DevOps
To jest dokładnie ten koszmar infrastrukturalny, który mają rozwiązywać platformy Backend-as-a-Service. Dzięki horizOn ta wzmocniona infrastruktura backendowa jest wstępnie skonfigurowana.
Zamiast spędzać miesiące na konfigurowaniu iptables, nasza platforma zarządza Edge network za Ciebie. Twoje instancje gry są chronione za warstwą routingu klasy enterprise, która automatycznie identyfikuje i odrzuca złośliwy ruch warstwy 4 i 7, zanim dotrze on do wątku serwera Unreal Engine. Oznacza to, że Twój Tick rate pozostaje stabilny, a gracze pozostają połączeni.
4 najlepsze praktyki dla deweloperów Indie pod atakiem
Stosuj te zasady bezpieczeństwa, aby wzmocnić swoją grę:
1. Nigdy nie ujawniaj adresów IP serwerów bezpośrednio klientom: Jeśli gracz może zobaczyć adres IP serwera przez Wireshark, atakujący również może. Korzystaj z bezpiecznej usługi Matchmaking lub biletów sesji.
2. Wdróż ścisłą walidację sesji:
Nie pozwalaj klientom łączyć się tylko na podstawie adresu IP i portu. Wymagaj krótkotrwałego tokenu kryptograficznego (jak JWT). Weryfikuj ten token natychmiast w PreLogin. Zapobiega to omijaniu limitów przez zmianę IP przez atakujących.
3. Ogranicz Tick rate serwera:
Nie uruchamiaj NetServerMaxTickRate bez ograniczeń. Zablokuj go na przewidywalnej wartości (30 Hz), aby procesor miał zapas na nieoczekiwane skoki ruchu.
4. Monitoruj brzeg sieci (Network Edge), a nie tylko silnik:
Logi silnika nie powiedzą Ci o pakietach odrzuconych na poziomie Firewalla. Musisz śledzić przepustowość przychodzącą (InBytes) na poziomie systemu operacyjnego. Nagły skok ruchu UDP bez wzrostu liczby graczy to główny wskaźnik ataku wolumetrycznego.
Ochrona gry to nieustanny wyścig zbrojeń. Wdrażając agresywny Rate Limiting i korzystając z infrastruktury odrzucającej ruch na brzegu sieci, zapewnisz graczom stabilną rozgrywkę.
Gotowy, by przestać martwić się infrastrukturą? Wypróbuj horizOn za darmo.
Źródło: [VERY CRITICAL] Organized DDoS Attacks Causing Server Crashes