جلوگیری از حملات DDoS: تشخیص حمله و مقابله با آن روی سرور لینوکس

جلوگیری از حملات DDoS: تشخیص حمله و مقابله با آن روی سرور لینوکس

سرور کند شده، سایت‌ها دیر بالا می‌آیند یا اصلاً باز نمی‌شوند و لود سرور بی‌دلیل بالا رفته است. اولین چیزی که به ذهن می‌رسد حمله DDoS است، اما قبل از اجرای هر دستوری باید مطمئن شوید واقعاً حمله‌ای در جریان است؛ یک اسکریپت خراب، یک کوئری سنگین دیتابیس یا یک بکاپ‌گیری بدموقع هم دقیقاً همین نشانه‌ها را می‌سازد و درمانشان کاملاً فرق می‌کند.

در ادامه، اول روش تشخیص حمله و بعد لایه‌به‌لایه راه‌های مقابله با آن روی یک سرور لینوکسی آمده است. دستورها برای توزیع‌های امروزی (AlmaLinux، Rocky Linux، CentOS Stream، Ubuntu و Debian) نوشته شده‌اند و هرجا روش قدیمی هنوز در اینترنت پیدا می‌شود، معادل درست امروزی‌اش هم آمده است.

یک هشدار قبل از شروع: تمام کارهای این مقاله فایروال و وب‌سرور را دست‌کاری می‌کنند و یک اشتباه می‌تواند دسترسی SSH خودتان را ببندد. پیش از اجرای هر دستور، مطمئن شوید یک راه دسترسی جایگزین (کنسول KVM، IPMI یا Rescue Mode سرویس‌دهنده) در اختیار دارید و از فایل‌های کانفیگی که ویرایش می‌کنید نسخه پشتیبان گرفته‌اید.

گام اول: مطمئن شوید واقعاً حمله در جریان است

شمردن اتصال‌های باز

ساده‌ترین نشانه یک حمله در لایه اتصال، تعداد غیرعادی کانکشن باز روی پورت وب است. ابزار استاندارد امروز برای این کار ss است:

# تعداد اتصال‌های برقرارشده روی پورت 80 و 443
ss -H -tn state established '( sport = :80 or sport = :443 )' | wc -l

# پرتکرارترین آی‌پی‌ها بر اساس تعداد اتصال
ss -H -tn state connected | awk '{print $4}' | sed 's/:[^:]*$//' | sort | uniq -c | sort -rn | head -20

# نشانه SYN Flood: تعداد زیاد اتصال در وضعیت SYN-RECV
ss -H -tn state syn-recv | wc -l

دو نکته درباره این دستورها: سوئیچ -H سطر عنوان جدول را حذف می‌کند تا خروجی wc -l دقیقاً برابر تعداد اتصال‌ها باشد (روی نسخه‌های خیلی قدیمی iproute2 که این سوئیچ را ندارند، یک واحد از عدد کم کنید). و در دستور دوم، sed 's/:[^:]*$//' فقط شماره پورت انتهایی را جدا می‌کند؛ برخلاف cut -d: -f1 که آدرس‌های IPv6 را خراب می‌کند.

دستورهای قدیمی‌تر با netstat هنوز همین کار را می‌کنند و اگر روی سرور در دسترس بود می‌توانید از آن‌ها استفاده کنید، اما توجه داشته باشید netstat بخشی از بسته منسوخ‌شده net-tools است و روی نصب‌های تازه معمولاً اصلاً وجود ندارد:

netstat -anp | grep 'tcp|udp' | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n

netstat -n | grep :80 | wc -l

نسخه کامل‌تر همین بررسی، همراه با تفکیک وضعیت اتصال‌ها و پورت‌ها، در مشاهده تعداد کانکشن‌ها و پیدا کردن آی‌پی مهاجم آمده است.

عدد جادویی وجود ندارد

در نوشته‌های قدیمی می‌خوانید که «بالای ۳۵۰ تا ۵۰۰ کانکشن یعنی حمله». این فقط یک قاعده سرانگشتی است و به‌تنهایی قابل اتکا نیست: روی سروری که چند سایت پربازدید میزبانی می‌کند، ۵۰۰ اتصال هم‌زمان کاملاً عادی است؛ و روی یک سرور کم‌ترافیک، ۱۰۰ اتصال هم‌زمان از یک آی‌پی واحد قطعاً غیرعادی است.

معیار درست، عدد عادی خود سرور شماست. همین امروز که حمله‌ای در کار نیست، خروجی دستورهای بالا را در ساعت‌های شلوغ و خلوت یادداشت کنید تا مبنای مقایسه داشته باشید. دو چیز بیش از عدد کل مهم است:

  • توزیع اتصال‌ها: اگر ۳۰۰ اتصال از ۳۰۰ آی‌پی مختلف باشد یعنی ترافیک عادی؛ اگر ۳۰۰ اتصال از ۵ آی‌پی باشد یعنی مشکل.
  • وضعیت اتصال‌ها: انبوه اتصال در وضعیت SYN-RECV نشانه SYN Flood است، و انبوه اتصال در وضعیت ESTABLISHED که هیچ داده‌ای رد و بدل نمی‌کنند نشانه حمله‌های کندکننده مثل Slowloris.

آی‌پی مهاجم و مسئله موقعیت جغرافیایی

پس از پیدا کردن آی‌پی‌های پرتکرار می‌توانید کشور آن‌ها را با سرویس‌هایی مثل ip2location.com بررسی کنید. اما به دو نکته دقت کنید تا مشتری واقعی خودتان را قطع نکنید:

  • «ایرانی نبودن آی‌پی» به‌تنهایی دلیل حمله نیست. اگر سایت شما از CDN یا پروکسی معکوس استفاده می‌کند، همه ترافیک با آی‌پی خارجی همان سرویس به سرور می‌رسد و بلاک کردن آن یعنی از دسترس خارج شدن کل سایت.
  • در حمله‌های بزرگ، ترافیک از بات‌نتی با هزاران آی‌پی می‌آید و در حمله‌های SYN Flood آی‌پی مبدأ اصولاً جعلی (spoofed) است؛ یعنی بلاک کردن تک‌تک آی‌پی‌ها بی‌فایده است و باید سراغ محدودسازی نرخ رفت.

آیا اصلاً کاری از دست سرور برمی‌آید؟

این را قبل از هر تنظیمی روشن کنید: اگر حجم ترافیک حمله از ظرفیت پورت شبکه سرور بیشتر باشد، پورت پیش از رسیدن بسته‌ها به فایروال اشباع شده است و هیچ قانون iptables یا CSF کمکی نمی‌کند، چون بسته‌ها اصلاً به سرور نمی‌رسند. در این حالت تنها راه، فیلتر شدن ترافیک در بالادست است: با پشتیبانی سرویس‌دهنده یا دیتاسنتر خود تماس بگیرید و از سرویس‌های محافظت در برابر DDoS یا یک CDN جلوی سایت استفاده کنید. تمام روش‌های بعدی این مقاله برای حمله‌هایی مؤثرند که سرور توان دریافتشان را دارد ولی توان پردازششان را ندارد.

گام دوم: تنظیم CSF (سریع‌ترین و مؤثرترین کار)

اگر CSF (ConfigServer Security & Firewall) روی سرور نصب است، بیشتر کاری که لازم دارید با چند گزینه در فایل تنظیماتش انجام می‌شود. اول یک نسخه پشتیبان بگیرید و بعد فایل را باز کنید:

cp /etc/csf/csf.conf /etc/csf/csf.conf.bak
vi /etc/csf/csf.conf

دقت کنید که نحو (syntax) این فایل به‌صورت NAME = "VALUE" است. مقدارها را با دو نقطه (:) ننویسید؛ نوشته‌های قدیمی این را اشتباه نقل کرده‌اند و CSF چنین خطی را نمی‌خواند. شکل درست این است:

PS_INTERVAL = "90"
PS_LIMIT = "10"
PORTFLOOD = "80;tcp;20;4"

معنای این سه گزینه:

  • PS_INTERVAL و PS_LIMIT مربوط به تشخیص پورت‌اسکن‌اند: در بازه ۹۰ ثانیه، اگر یک آی‌پی بیش از ۱۰ بار به پورت‌های بسته بخورد بلاک می‌شود. مقدار 0 برای PS_INTERVAL یعنی غیرفعال. برای اینکه این قابلیت کار کند باید PS_PORTS هم تعریف شده باشد.
  • PORTFLOOD قالب پورت;پروتکل;تعداد;ثانیه دارد. مقدار بالا یعنی «اگر یک آی‌پی در ۴ ثانیه بیش از ۲۰ اتصال به پورت ۸۰ TCP باز کرد، بلاکش کن».

دو گزینه دیگر هم هستند که در عمل بیشترین اثر را روی حمله‌های HTTP دارند:

CT_LIMIT = "100"
CT_INTERVAL = "30"
CT_BLOCK_TIME = "1800"
CT_PERMANENT = "0"
CT_PORTS = "80,443"

CONNLIMIT = "80;30,443;30"
  • CT_LIMIT (Connection Tracking) هر CT_INTERVAL ثانیه اتصال‌ها را می‌شمارد و آی‌پی‌ای که بیش از حد تعیین‌شده اتصال هم‌زمان داشته باشد را بلاک می‌کند. حتماً CT_PERMANENT = "0" بگذارید تا بلاک موقت باشد و بعد از CT_BLOCK_TIME (اینجا ۱۸۰۰ ثانیه) خودبه‌خود برداشته شود؛ وگرنه بلاک‌ها دائمی می‌شوند و به‌مرور کاربران واقعی را هم از دست می‌دهید. مقدار CT_INTERVAL را زیر ۳۰ ثانیه نگذارید، چون شمارش مکرر خودش به سرور بار می‌آورد. کاری که این گزینه می‌کند دقیقاً همان کاری است که اسکریپت‌های جانبی مثل DDoS-Deflate انجام می‌دادند، منتها به‌صورت بومی و پشتیبانی‌شده.
  • CONNLIMIT سقف اتصال هم‌زمان هر آی‌پی به هر پورت را تعیین می‌کند؛ مقدار بالا یعنی هر آی‌پی حداکثر ۳۰ اتصال هم‌زمان به پورت ۸۰ و ۳۰ اتصال به ۴۴۳.

گزینه SYNFLOOD هم وجود دارد، ولی آن را فقط زمانی روشن کنید که واقعاً زیر SYN Flood هستید؛ خود مستندات CSF هشدار می‌دهد که این قابلیت پرهزینه است و روی سرور بدون حمله، سرعت برقراری همه اتصال‌ها را پایین می‌آورد.

قبل از ری‌استارت، خودتان را قفل بیرون نکنید. این گزینه‌ها اتصال‌ها را بر اساس تعداد می‌بندند و اگر شما و همکارانتان پشت یک آی‌پی مشترک (NAT دفتر) باشید، ممکن است خودتان قربانی شوید. آی‌پی خودتان، آی‌پی سرویس مانیتورینگ و آی‌پی سرویس‌های پرداخت را در لیست سفید بگذارید و مطمئن شوید پورت SSH سرور در TCP_IN هست:

csf -a 203.0.113.10 admin office

بعد از هر تغییر در csf.conf حتماً فایروال را ری‌استارت کنید و مطمئن شوید حالت آزمایشی خاموش است (یعنی TESTING = "0")، وگرنه قوانین هر بار پاک می‌شوند:

csf -r

اگر مطمئن نیستید تنظیماتتان درست است، عمداً TESTING را روی "1" بگذارید و اول قوانین را آزمایش کنید؛ در این حالت یک کران‌جاب هر پنج دقیقه فایروال را پاک می‌کند و اگر دسترسی خودتان قطع شد، حداکثر پنج دقیقه بعد برمی‌گردد.

گام سوم: مسدود کردن دستی آی‌پی مهاجم

پیش از بلاک کردن هر آی‌پی، یک بار مطمئن شوید که آن آی‌پی متعلق به خودتان، به CDN یا پروکسی جلوی سایت، به سرویس مانیتورینگ یا به درگاه پرداخت نیست. بستن آی‌پی CDN یعنی خاموش کردن کل سایت با دست خودتان.

اگر CSF دارید، ساده‌ترین و ماندگارترین راه همین است (بلاک پس از ری‌بوت هم باقی می‌ماند):

csf -d 218.92.207.28 DDoS attack

# بررسی اینکه یک آی‌پی بلاک شده یا نه
csf -g 218.92.207.28

# برداشتن بلاک
csf -dr 218.92.207.28

اگر CSF ندارید، مستقیم با iptables:

iptables -I INPUT -s 218.92.207.28 -j DROP

نکته مهم درباره ماندگاری قانون: دستور قدیمی service iptables save فقط روی CentOS 6 و روی سیستم‌هایی که بسته iptables-services نصب دارند کار می‌کند. روی سیستم‌های امروزی:

# Debian / Ubuntu (بسته iptables-persistent)
netfilter-persistent save

# AlmaLinux / Rocky / CentOS با بسته iptables-services
iptables-save > /etc/sysconfig/iptables
systemctl restart iptables

# اگر firewalld فعال است، به‌جای iptables از این استفاده کنید
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="218.92.207.28" drop'
firewall-cmd --reload

حواستان باشد که این سه روش را با هم قاطی نکنید؛ اگر firewalld فعال است، قوانینی که مستقیم با iptables اضافه کنید با اولین firewall-cmd --reload از بین می‌روند. اگر CSF نصب است هم قانون دستی iptables با اولین csf -r پاک می‌شود، پس روی سرور دارای CSF از csf -d استفاده کنید نه از iptables.

وقتی تعداد آی‌پی‌ها زیاد شد، اضافه کردن صدها قانون جداگانه به iptables خودش سرور را کند می‌کند. راه درست ipset است:

ipset create ddos hash:ip hashsize 4096 timeout 3600
iptables -I INPUT -m set --match-set ddos src -j DROP

ipset add ddos 218.92.207.28

گزینه timeout 3600 باعث می‌شود آی‌پی‌ها بعد از یک ساعت خودبه‌خود آزاد شوند؛ این جلوی انباشته شدن بلاک‌های قدیمی و قطع شدن کاربران واقعی را می‌گیرد. توجه کنید که ipset با ری‌بوت پاک می‌شود؛ اگر می‌خواهید بماند باید آن را ذخیره کنید و دقت داشته باشید که ست باید پیش از بازگردانی قوانین iptables ساخته شود، وگرنه بازگردانی با خطای «Set cannot be destroyed» شکست می‌خورد و ممکن است سرور بدون فایروال بالا بیاید:

ipset save > /etc/ipset.conf

درباره APF

در دستورالعمل‌های قدیمی، نصب فایروال APF و روشن کردن گزینه USE_AD = 1 در /etc/apf/conf.apf و افزودن آی‌پی به /etc/apf/deny_hosts.rules و سپس service apf restart توصیه می‌شد. این روش امروز منسوخ است: APF سال‌هاست به‌طور فعال توسعه داده نمی‌شود و ماژول antidos آن هم همراهش. اگر روی سروری هنوز APF دارید، جایگزین درست همان CSF است که در بالا آمد؛ روی یک سرور هم نباید هم‌زمان APF و CSF فعال باشند چون قوانین یکدیگر را خراب می‌کنند.

بلاک در سطح وب‌سرور

گاهی لازم است آی‌پی را فقط برای یک سایت ببندید، نه کل سرور. در Apache 2.4 (نسخه‌ای که امروز روی تقریباً همه سرورها اجرا می‌شود) نحو صحیح این است:

<RequireAll>
    Require all granted
    Require not ip 218.92.207.28
</RequireAll>

نحو قدیمی Apache 2.2 که هنوز در بسیاری از آموزش‌ها دیده می‌شود، شکل زیر بود. اگر با آن روبه‌رو شدید بدانید روی Apache 2.4 بدون ماژول mod_access_compat کار نمی‌کند و بهتر است به شکل بالا بازنویسی شود:

Order allow,deny
Allow from all
Deny from 218.92.207.28

اگر سایت پشت CDN یا پروکسی معکوس است، آی‌پی‌ای که Apache می‌بیند آی‌پی پروکسی است نه بازدیدکننده؛ در این حالت بلاک بر اساس آی‌پی در وب‌سرور بی‌اثر (یا فاجعه‌بار) است، مگر اینکه ماژول mod_remoteip را درست تنظیم کرده باشید.

گام چهارم: mod_evasive روی Apache

ماژول mod_evasive (که قبلاً mod_dosevasive نام داشت) درخواست‌های پرتکرار به یک صفحه یا یک سایت را می‌شمارد و آی‌پی پرتکرار را موقتاً بلاک می‌کند. دستورالعمل‌های قدیمی، کامپایل دستی نسخه 1.10.1 با apxs برای Apache 1.3 را توضیح می‌دادند؛ Apache 1.3 سال‌هاست پایان عمر شده و دیگر نیازی به کامپایل دستی نیست. از مخزن توزیع نصب کنید:

# AlmaLinux / Rocky / CentOS Stream (نیازمند مخزن EPEL)
dnf install epel-release
dnf install mod_evasive

# Debian / Ubuntu
apt install libapache2-mod-evasive
a2enmod evasive

روی سرورهای cPanel در فعال کردن EPEL احتیاط کنید؛ این مخزن می‌تواند بسته‌های خود cPanel را با نسخه‌های ناسازگار جایگزین کند. اگر مجبورید از آن استفاده کنید، مخزن را غیرفعال نگه دارید و فقط با --enablerepo=epel برای همان یک بسته موقتاً روشنش کنید.

تنظیمات ماژول همان دایرکتیوهای قدیمی است و تغییری نکرده است؛ آن‌ها را در فایل کانفیگ ماژول قرار دهید (روی AlmaLinux/Rocky در /etc/httpd/conf.d/mod_evasive.conf و روی Ubuntu در /etc/apache2/mods-available/evasive.conf):

DOSHashTableSize 3097
DOSPageCount 5
DOSSiteCount 50
DOSPageInterval 1
DOSSiteInterval 1
DOSBlockingPeriod 10
DOSWhitelist 127.0.0.1

دو هشدار عملی: مقدار DOSPageCount 2 که در نوشته‌های قدیمی توصیه می‌شد به‌شدت سخت‌گیرانه است و کاربران واقعی را هم بلاک می‌کند؛ با ۵ شروع کنید و در صورت نیاز پایین بیاورید. همچنین حتماً آی‌پی خودتان، آی‌پی سرویس مانیتورینگ و آی‌پی سرویس‌های پرداخت را در DOSWhitelist بگذارید (این دایرکتیو برای هر آی‌پی یک بار تکرار می‌شود).

برای اعمال تنظیمات، وب‌سرور را ری‌استارت کنید. دستور قدیمی /etc/init.d/httpd restart روی توزیع‌های امروزی که از systemd استفاده می‌کنند جای خود را به این‌ها داده است:

# AlmaLinux / Rocky / CentOS
systemctl restart httpd

# Debian / Ubuntu
systemctl restart apache2

# روی سرورهای cPanel
/scripts/restartsrv_httpd

قبل از ری‌استارت، صحت فایل کانفیگ را با apachectl configtest بررسی کنید؛ یک خطای تایپی در کانفیگ باعث می‌شود وب‌سرور بعد از ری‌استارت اصلاً بالا نیاید.

گام پنجم: ModSecurity

ModSecurity یک فایروال لایه اپلیکیشن است و جلوی درخواست‌های مخرب HTTP را می‌گیرد. توجه داشته باشید که این ابزار در برابر SYN Flood یا حمله‌های حجمی UDP کاری از دستش برنمی‌آید؛ حوزه کارش درخواست‌های HTTP است.

مسیر قدیمی WHM » cPanel » Addon Modules مربوط به دوران EasyApache 3 است و دیگر وجود ندارد. روی cPanel امروزی (EasyApache 4):

  • نصب ماژول: WHM » Software » EasyApache 4 و انتخاب بسته ea-apache24-mod_security2 (یا با دستور dnf install ea-apache24-mod_security2).
  • تنظیمات و روشن/خاموش کردن آن برای هر دامنه: WHM » Security Center » ModSecurity™ Configuration.
  • فعال کردن مجموعه قوانین (مثلاً OWASP CRS): WHM » Security Center » ModSecurity™ Vendors.

روی سرورهای بدون کنترل‌پنل، نام بسته به توزیع بستگی دارد: روی AlmaLinux/Rocky بسته mod_security از مخزن EPEL و روی Debian/Ubuntu بسته libapache2-mod-security2؛ مجموعه قوانین OWASP CRS هم جداگانه اضافه می‌شود. بعد از فعال کردن قوانین، اول چند روز آن را در حالت فقط ثبت لاگ (SecRuleEngine DetectionOnly) بگذارید و لاگ‌ها را بررسی کنید؛ قوانین سخت‌گیرانه به‌راحتی فرم‌ها و پنل مدیریت سایت خودتان را هم بلاک می‌کنند.

گام ششم: تنظیم مقادیر Apache

مسیر فایل کانفیگ به توزیع و کنترل‌پنل بستگی دارد. مسیر قدیمی /usr/local/apache/conf/httpd.conf مربوط به EasyApache 3 است:

  • cPanel با EasyApache 4: /etc/apache2/conf/httpd.conf — این فایل بازتولید می‌شود و تغییرات دستی‌تان پاک می‌شود، پس آن را مستقیم ویرایش نکنید و از WHM » Service Configuration » Apache Configuration » Global Configuration یا از Include Editor در همان منو استفاده کنید.
  • AlmaLinux / Rocky / CentOS بدون کنترل‌پنل: /etc/httpd/conf/httpd.conf
  • Debian / Ubuntu: /etc/apache2/apache2.conf

حالا مهم‌ترین تصحیح این بخش: توصیه قدیمی «KeepAliveTimeout را از ۳۰ به ۶۰ ببرید» درست نیست و در زمان حمله دقیقاً نتیجه معکوس می‌دهد. هر اتصال باز، یک worker از وب‌سرور را اشغال نگه می‌دارد؛ در حمله‌های اشباع اتصال، هرچه این عدد بزرگ‌تر باشد سرور زودتر پر می‌شود. مقدار پیش‌فرض Apache 2.4 عدد ۵ است و زیر فشار باید همان یا کمتر بماند:

KeepAliveTimeout 5
MaxKeepAliveRequests 100
Timeout 30

درباره MaxKeepAliveRequests هم توصیه قدیمی «از ۱۰۰ به ۵۰ کم کنید» عملاً اثر محسوسی روی حمله ندارد؛ اهرم اصلی همان KeepAliveTimeout است. اگر سرور واقعاً زیر حمله اشباع اتصال است، مؤثرترین کار خاموش کردن موقت keep-alive با KeepAlive Off است. این کار را دائمی نکنید: در ترافیک عادی، تعداد هندشیک‌های TCP و TLS و در نتیجه مصرف CPU را بالا می‌برد؛ بعد از پایان حمله برش گردانید.

درباره تعداد پردازش‌ها هم دو نکته نسخه‌ای هست:

  • دایرکتیو MaxClients در Apache 2.4 به MaxRequestWorkers تغییر نام داده است. نام قدیمی هنوز به‌عنوان مترادف پذیرفته می‌شود ولی منسوخ است.
  • MinSpareServers و MaxSpareServers فقط برای MPM prefork معنا دارند. اگر سرور شما با MPM event یا worker اجرا می‌شود (که روی نصب‌های امروزی رایج‌تر است) معادل‌های آن‌ها MinSpareThreads و MaxSpareThreads هستند.

برای اینکه بدانید کدام MPM فعال است:

httpd -V | grep -i mpm      # AlmaLinux / Rocky / CentOS
apache2ctl -V | grep -i mpm # Debian / Ubuntu

در تعیین MaxRequestWorkers زیاده‌روی نکنید. عدد بزرگ یعنی در زمان حمله سرور به‌جای رد کردن درخواست‌ها، حافظه را تمام می‌کند و به OOM می‌خورد. مقدار منطقی از تقسیم حافظه قابل تخصیص بر میانگین مصرف حافظه هر پردازش Apache به دست می‌آید.

اگر Nginx دارید

روی سرورهایی که Nginx جلوی وب‌سرور است، محدودسازی نرخ درخواست بومی و بسیار مؤثر است:

# در بخش http
limit_req_zone $binary_remote_addr zone=perip:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=connperip:10m;

# در بخش server
limit_req zone=perip burst=20 nodelay;
limit_conn connperip 20;

پیش از اعمال، با nginx -t کانفیگ را تست کنید و بعد systemctl reload nginx بزنید. اگر Nginx پشت CDN است، متغیر $binary_remote_addr آی‌پی CDN را می‌گیرد نه بازدیدکننده را؛ در آن حالت باید ماژول real_ip را تنظیم کنید وگرنه کل ترافیک سایت به‌عنوان یک آی‌پی محدود می‌شود.

گام هفتم: سخت‌سازی سطح کرنل در برابر SYN Flood

ماژول antidos فایروال APF کارش شمردن اتصال‌ها و بلاک کردن آی‌پی‌های پرتکرار بود (همان نقشی که امروز CT_LIMIT در CSF دارد)؛ اما لایه‌ای که به‌طور مشخص جلوی SYN Flood را می‌گیرد، خود کرنل است. یک فایل در /etc/sysctl.d/ بسازید (مثلاً 99-ddos.conf) و این مقادیر را در آن بگذارید:

net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 4096
net.ipv4.tcp_synack_retries = 2

سپس اعمالشان کنید:

sysctl --system

گزینه tcp_syncookies روی کرنل‌های امروزی معمولاً از پیش روشن است؛ با sysctl net.ipv4.tcp_syncookies وضعیتش را ببینید. از کپی کردن فهرست‌های بلندبالای «tuning» که در اینترنت پیدا می‌شوند خودداری کنید؛ بعضی از آن پارامترها (مثل tcp_tw_recycle) سال‌هاست از کرنل حذف شده‌اند و بعضی دیگر پشت NAT ارتباط کاربران واقعی را قطع می‌کنند.

گام هشتم: اسکریپت‌های جانبی مثل DDoS-Deflate

اسکریپت DDoS-Deflate سال‌ها به‌عنوان راه‌حل سریع معرفی می‌شد. نصب آن به این شکل بود:

wget http://www.inetbase.com/scripts/ddos/install.sh
sh install.sh

# و سپس افزودن این خط به crontab با دستور crontab -e
*/5 * * * * /usr/local/ddos/ddos.sh >/dev/null 2>&1

این آدرس دیگر در دسترس نیست و نسخه اصلی اسکریپت هم سال‌هاست نگهداری نمی‌شود؛ اجرای اسکریپتی که با wget از یک دامنه رهاشده گرفته شود، خودش یک ریسک امنیتی است و اصلاً این دستور را روی سرور واقعی اجرا نکنید — اینجا فقط برای این آورده شده که اگر در آموزش‌های قدیمی دیدیدش بدانید چیست. کاری که این اسکریپت انجام می‌داد — شمردن اتصال هر آی‌پی و بلاک کردن آی‌پی‌های بیش از حد — دقیقاً همان CT_LIMIT در CSF است که در گام دوم آمد. اگر CSF دارید، به این اسکریپت نیازی ندارید. اگر حتماً می‌خواهید از خود اسکریپت استفاده کنید، سراغ نسخه‌های فورک‌شده‌ای بروید که هنوز روی GitHub نگهداری می‌شوند و کد را پیش از اجرا بخوانید.

گام نهم: پیدا کردن و مهار سایت هدف

روی سرور اشتراکی معمولاً حمله به یک دامنه خاص است و بقیه سایت‌ها قربانی جانبی می‌شوند. برای پیدا کردن آن دامنه، حجم لاگ دسترسی سایت‌ها را مقایسه کنید (روی cPanel با EasyApache 4، لاگ‌ها معمولاً در /etc/apache2/logs/domlogs/ هستند):

ls -lS /etc/apache2/logs/domlogs/ | head -20

# پرتکرارترین آی‌پی‌ها در لاگ یک دامنه (هم HTTP و هم HTTPS)
awk '{print $1}' /etc/apache2/logs/domlogs/example.com /etc/apache2/logs/domlogs/example.com-ssl_log | sort | uniq -c | sort -rn | head -20

# پرتکرارترین آدرس‌های درخواست‌شده
awk '{print $7}' /etc/apache2/logs/domlogs/example.com /etc/apache2/logs/domlogs/example.com-ssl_log | sort | uniq -c | sort -rn | head -20

حتماً فایل -ssl_log را هم در بررسی بیاورید؛ امروز بیشتر ترافیک روی HTTPS است و اگر فقط فایل بدون پسوند را نگاه کنید، بخش اصلی حمله را اصلاً نمی‌بینید.

خروجی دستور آخر مهم‌ترین سرنخ را می‌دهد: اگر همه درخواست‌ها روی یک مسیر سنگین مثل صفحه جستجو یا xmlrpc.php و wp-login.php متمرکز است، پیش از هر کار دیگری همان مسیر را ببندید — این کار معمولاً بار سرور را بلافاصله پایین می‌آورد.

اگر یک سایت واقعاً کل منابع سرور را می‌بلعد و راهی برای فیلتر کردنش نیست، به‌عنوان آخرین راه می‌توانید حسابش را موقتاً معلق کنید تا بقیه سایت‌ها بالا بمانند. در cPanel این کار از مسیر WHM » Account Functions » Suspend/Unsuspend an Account انجام می‌شود و مصرف پهنای باند هر حساب هم از WHM » Account Information » View Bandwidth Usage قابل مشاهده است. طبیعتاً پیش از انجام این کار به صاحب سایت اطلاع بدهید؛ تعلیق حساب سایت او را کامل از دسترس خارج می‌کند.

یک احتمال دیگر را هم فراموش نکنید: گاهی سرور «زیر حمله» نیست، بلکه یکی از سایت‌هایش هک شده و خودش دارد به بیرون حمله می‌کند یا اسپم می‌فرستد. اگر ترافیک خروجی غیرعادی است، مسئله امنیتی است نه DDoS.

جمع‌بندی: ترتیب کارها هنگام حمله

  • با ss تعداد و توزیع اتصال‌ها را ببینید و مطمئن شوید مسئله واقعاً حمله است، نه یک اسکریپت یا کوئری خراب.
  • اگر حجم حمله از ظرفیت پورت شبکه بیشتر است، بلافاصله سراغ سرویس‌دهنده و راهکار بالادستی بروید؛ تنظیم سرور بی‌فایده است.
  • پیش از دست زدن به فایروال، آی‌پی خودتان را در لیست سفید بگذارید و راه دسترسی جایگزین (کنسول/Rescue) را آماده داشته باشید.
  • در CSF گزینه‌های CT_LIMIT، CONNLIMIT و PORTFLOOD را تنظیم کنید و csf -r بزنید.
  • آی‌پی‌های مشخصاً مهاجم را با csf -d یا ipset ببندید — نه با صدها قانون تکی iptables.
  • در سطح وب‌سرور، KeepAliveTimeout را پایین نگه دارید، MaxRequestWorkers را متناسب با حافظه تنظیم کنید و mod_evasive یا limit_req در Nginx را فعال کنید.
  • مسیر یا دامنه هدف را از روی لاگ‌ها پیدا کنید و همان را محدود کنید.
  • بعد از پایان حمله، بلاک‌های موقت را بردارید و تنظیم‌های اضطراری مثل KeepAlive Off را برگردانید تا کاربران واقعی قطع نمانند.