لماذا تتجمد Dedicated Servers الخاصة بك: حقيقة DDoS Protection لخوادم Unreal Engine
يخشى كل مطور ألعاب Multiplayer من تجمد الخادم المفاجئ وغير المبرر. يعمل مثيلك المخصص بشكل مثالي بمعدل Tick rate ثابت يبلغ 30، ثم، بدون سابق إنذار، تتوقف المحاكاة بأكملها. يعاني اللاعبون من Rubber-banding عبر الخريطة، وتسقط RPCs، وبعد لحظات، تنهي مهلة الاتصال الكارثية Connection timeout المباراة. قد تلوم غريزيًا أحدث كود لـ Movement replication أو حساب فيزيائي معقد، ولكن إذا كانت قاعدة لاعبيك تنمو، فالحقيقة غالبًا ما تكون أكثر خبثًا: بنيتك التحتية ضحية لهجوم منظم لتعطيل الخدمة Distributed Denial of Service (DDoS).
تسلط التقارير الأخيرة من مجتمع مطوري Unreal Engine الضوء على ارتفاع هائل في هجمات DDoS المنظمة التي تستهدف خوادم الألعاب، وتؤثر بشكل خاص على الأنماط واسعة النطاق مثل Battle Royale ومثيلات Creative المخصصة. تغمر هذه الهجمات مؤشر معالجة الشبكة Network processing thread في الخادم تمامًا، مما يؤدي إلى Lag شديد، وعدم مزامنة عالمية، وفي النهاية، Hard crashes.
بالنسبة للمطورين Indie واستديوهات AA، لم يعد تنفيذ حماية قوية Unreal Engine Server DDoS Protection اختياريًا - بل أصبح مطلبًا إلزاميًا لأي لعبة Live-ops. في هذا التحليل الفني، سنحلل كيف تتلاعب هذه الهجمات بـ Netcode الخاص بـ Unreal Engine، وكيفية التمييز بين التدفق الخبيث وظروف الشبكة السيئة القياسية، والخطوات الملموسة التي يمكنك اتخاذها لتقوية بنية لعبتك التحتية.
تشريح تعطل خادم Unreal Engine
لفهم كيفية حماية خادمك، عليك أولاً أن تفهم كيف يعالج Unreal Engine حركة مرور الشبكة الواردة. يستخدم Unreal بروتوكولاً مخصصًا يعتمد على UDP يديره NetDriver. ولأن UDP عديم الاتصال، يمكن لأي عميل على الإنترنت إرسال حزم إلى منفذ خادمك المفتوح دون Handshake رسمي.
هجمات التدفق الحجمي Layer 4 مقابل هجمات التطبيقات Layer 7
تحدث معظم أعطال الخوادم بسبب أحد نوعين من الهجمات على الشبكة:
1. تدفقات UDP الحجمية (Layer 4): هذا هجوم بالقوة الغاشمة. تقوم Botnet بقصف عنوان IP العام للخادم ومنفذه بجيجابايت من حزم UDP غير الصالحة في الثانية. تصبح بطاقة واجهة الشبكة (NIC) ونظام الشبكة في نظام التشغيل Network stack مشبعين تمامًا. قبل أن تتاح لـ Unreal Engine فرصة للنظر في الحزم، تنفد Bandwidth من الجهاز الأساسي أو تتوقف معالجة CPU interrupts، مما يؤدي إلى إسقاط حركة مرور اللاعبين الشرعيين تمامًا.
2. استنفاد طبقة التطبيقات (Layer 7):
هذه الهجمات أكثر دهاءً بكثير. بدلاً من إرسال نفايات عشوائية، يستخدم المهاجم أدوات Packet capture أو عملاء ألعاب معدلين لإرسال طلبات اتصال Unreal Engine منسقة بشكل صحيح (مثل حزم NMT_Hello أو NMT_Login) أو رسائل RPC ثقيلة محددة. يقبل NetDriver هذه الحزم التي تبدو صالحة ويسلمها إلى Game thread للمعالجة. يرتفع استهلاك وحدة المعالجة المركزية للخادم إلى 100% أثناء محاولته تحليل الآلاف من عمليات Handshake الوهمية، أو التحقق من تذاكر الجلسة غير الموجودة، أو تخصيص الذاكرة لمعلمات سلسلة معقدة في الوظائف المكررة. نظراً لأن حركة المرور هذه تبدو مطابقة لنشاط اللاعب الشرعي بالنسبة لـ Firewall القياسي، فإنها تتجاوز حماية DDoS الأساسية. يؤدي هذا فوراً إلى انهيار Tick rate للخادم، مما يتسبب في سلوكيات الانتقال الآني والرجوع Rollback التي يواجهها اللاعبون قبل أن تنهي عملية Watchdog المثيل المتجمد.
تشخيص الهجوم: هل هو خبيث أم مجرد Netcode سيء؟
قبل أن تفترض أن خادمك يتعرض للهجوم، يجب عليك استبعاد أخطاء Replication الكارثية. إذا قام عميل واحد بتشغيل حلقة لا نهائية من استدعاءات RPC، فيمكنه محاكاة DDoS من الطبقة 7. قبل الدخول في حالة ذعر، يجب عليك مراجعة سجلات التعطل والمقاييس. إذا كنت ترى ارتفاعات هائلة في Memory allocation ولكن حركة مرور الشبكة منخفضة، فقد تكون تتعامل مع مشكلة في Replication - للحصول على إرشادات حول ذلك، راجع دليلنا Zero Ping Spikes Complete Freeze The Ultimate Uefn Server Crash Fix Protocol.
ومع ذلك، إذا أظهرت المراقبة الخارجية ارتفاع حركة المرور الواردة من خط أساس يبلغ ~50 ميجابت في الثانية إلى 5 جيجابت في الثانية، أو إذا أظهرت سجلات الخادم آلاف رسائل LogNet: NotifyAcceptingConnection من عناوين IP فريدة في غضون ثوانٍ، فأنت تتعامل مع هجوم منسق.
تقوية Netcode الخاص بك: تنفيذ تقييد الاتصال في C++
بينما يجب أن يحدث تخفيف DDoS الحجمي الحقيقي على مستوى البنية التحتية (والذي سنغطيه قريباً)، يمكنك حماية خادم Unreal Engine الخاص بك من استنفاد الطبقة 7 عن طريق تنفيذ Rate Limiting صارم مباشرة في AGameModeBase.
من خلال تجاوز وظيفة PreLogin ، يمكنك اعتراض محاولات الاتصال قبل أن يخصص الخادم APlayerController كاملاً ويبدأ العملية المكلفة لتحميل اللاعب في العالم.
إليك تنفيذ قوي بـ C++ لتقييد محاولات الاتصال السريعة من عناوين IP الخبيثة:
// 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);
}
لماذا هذا الكود مهم
يتتبع هذا التنفيذ عنوان IP لكل طلب وارد. إذا حاول عنوان IP واحد الاتصال أكثر من 4 مرات في غضون 60 ثانية، يرفض الخادم الاتصال بنشاط في PreLogin. رفض الاتصال هنا أرخص بكثير في دورات وحدة المعالجة المركزية من السماح للمحرك بإنشاء Actor، وتكرار الحالات الأولية، ثم طرد اللاعب. يمكن لهذه المجموعة البسيطة من التعليمات البرمجية أن تحدث فرقاً بين بقاء خادمك في مواجهة هجوم من الطبقة 7 وتعطله تماماً.
ضبط تكوين شبكة Unreal Engine
بالإضافة إلى منطق C++، يحتوي ملف DefaultEngine.ini على العديد من معلمات التكوين الهامة. ترك هذه المعلمات في إعداداتها الافتراضية يعد ثغرة أمنية كبيرة. إذا قام مهاجم بغمر خادمك وكانت حدود Bandwidth غير محددة، فسيحاول الخادم معالجة كل شيء، مما يؤدي إلى استهلاك وحدة المعالجة المركزية بالكامل فوراً.
يجب عليك وضع حدود عليا صارمة لحركة مرور الشبكة. افتح DefaultEngine.ini وقم بتطبيق هذه الحدود المقواة على 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
من خلال تقليل ConnectionTimeout إلى 15.0 ثانية، سيقوم خادمك بسرعة بتطهير الاتصالات نصف المفتوحة أو الميتة الناتجة عن هجوم DDoS، مما يوفر الذاكرة وفتحات الشبكة للاعبين الشرعيين.
مشكلة البنية التحتية: لا يمكنك حظر ما وصل بالفعل
ستحميك تكوينات تقييد C++ و INI الموضحة أعلاه من استنفاد طبقة التطبيقات، لكنها تشترك في عيب قاتل عندما يتعلق الأمر بهجمات الطبقة 4 الحجمية: بحلول الوقت الذي يقرر فيه خادم Unreal Engine الخاص بك إسقاط الحزمة، يكون قد تم استهلاك Bandwidth بالفعل.
إذا وجه المهاجم Botnet بقوة 10 جيجابت في الثانية إلى خادمك، وكان موفر الاستضافة الخاص بك يوفر واجهة شبكة بقوة 1 جيجابت في الثانية فقط، فلا يهم مدى تحسين كود C++ الخاص بك. الأنابيب المؤدية إلى خادمك مسدودة جسدياً. لا يمكن لحركة مرور اللاعبين الشرعيين المرور.
يتطلب تخفيف هجمات الطبقة 4 استراتيجية دفاع على مستوى البنية التحتية.
نهج "افعل ذلك بنفسك"
إذا كنت تقوم بتشغيل خوادمك المخصصة Bare-metal أو مثيلات EC2 القياسية، فعليك بناء خط أنابيب للتخفيف يدوياً. يتضمن هذا عادةً:
- إعداد Reverse Proxy: لا يمكنك كشف عنوان IP الفعلي لخادم Unreal Engine للجمهور. يجب عليك توجيه حركة المرور عبر وكيل UDP (مثل NGINX أو HAProxy). يضيف هذا زمن انتقال، ولكنه يسمح لك بإخفاء IP الحقيقي.
- تكوين iptables/nftables: يجب عليك كتابة قواعد Firewall صارمة لإسقاط حزم UDP المجزأة وتقييد الاتصالات لكل IP على مستوى النواة.
- شراء خدمات التخفيف للمؤسسات: عليك شراء خدمات توجيه باهظة الثمن (مثل AWS Shield Advanced أو Cloudflare Magic Transit) لتنظيف حركة المرور الضارة قبل وصولها إلى مركز البيانات الخاص بك.
يتطلب بناء هذه الهندسة المرنة القائمة على الوكيل بنفسك إعداد مديري الأساطيل، و Load balancers، وجداول توجيه معقدة - ما يعادل 4-6 أشهر من عمل DevOps المتخصص. إنه استنزاف مالي وزمني هائل لاستوديو Indie يحاول شحن لعبة.
الهروب من فخ DevOps
هذا هو بالضبط كابوس البنية التحتية الذي صممت منصات Backend-as-a-Service لحله. مع horizOn ، تأتي هذه البنية التحتية المقواة مهيأة مسبقاً.
بدلاً من قضاء أشهر في تكوين iptables والقلق بشأن تدفقات UDP الحجمية، تدير منصتنا Edge network نيابة عنك. مثيلات لعبتك محمية خلف طبقة توجيه على مستوى المؤسسات تحدد وتسقط حركة مرور Layer 4 و Layer 7 الضارة تلقائياً قبل أن تصل إلى خادم Unreal Engine الفعلي. وهذا يعني أن Tick rate يظل مستقراً، ويظل لاعبونك الشرعيون متصلين.
4 ممارسات فضلى للمطورين Indie الذين يتعرضون للهجوم
اتبع هذه المبادئ الأمنية الأساسية لتقوية لعبتك:
1. لا تكشف أبداً عن عناوين IP للخوادم مباشرة للعملاء: استخدم خدمة Matchmaking آمنة أو تذاكر جلسة.
2. تنفيذ التحقق الصارم من الجلسة: لا تسمح للعملاء بالاتصال بمجرد معرفة IP والمنفذ. اطلب رمزاً مشفراً (مثل JWT) يتم تمريره في سلسلة الاتصال. تحقق من هذا الرمز فوراً في PreLogin.
3. تحديد معدل Tick rate للخادم: لا تقم بتشغيل NetServerMaxTickRate غير محدود. قم بقفله عند قيمة يمكن التنبؤ بها (30 هرتز).
4. مراقبة حافة الشبكة Network Edge وليس المحرك فقط: لن تخبرك سجلات تعطل المحرك عن الحزم التي تم إسقاطها عند Firewall. يجب أن يكون لديك مقاييس لتتبع Bandwidth الواردة (InBytes) على مستوى نظام التشغيل.
حماية لعبتك هي سباق تسلح مستمر. من خلال تنفيذ تقييد صارم في الكود الخاص بك واستخدام بنية تحتية تسقط حركة المرور السيئة عند الحافة، يمكنك ضمان تجربة لعب مستقرة.
هل أنت مستعد للتوقف عن القلق بشأن البنية التحتية؟ جرب horizOn مجاناً.
المصدر: [VERY CRITICAL] Organized DDoS Attacks Causing Server Crashes