محدود کردن درخواست در Nginx با limit_req

برای محدود کردن درخواست در Nginx از دو ماژول داخلی استفاده می‌کنید: limit_req تعداد درخواست در بازه زمانی را محدود می‌کند و limit_conn تعداد اتصال هم‌زمان را. با چند خط تنظیم می‌توانید جلوی حدس رمز روی wp-login.php، اسکریپت‌های پرتکرار و فشار ناگهانی روی سایت را بگیرید و به‌جای قطعی کامل، به درخواست‌های اضافه پاسخ 429 بدهید.

این روش جایگزین فایروال نیست و پوشش مکمل آن است. برای مسدود کردن دائمی آدرس‌های مهاجم، نصب و تنظیم Fail2ban را هم ببینید. اگر Nginx ندارید، ابتدا نصب Nginx روی اوبونتو را انجام دهید.

limit_req: چطور کار می‌کند؟

Nginx با الگوریتم «سطل نشتی» (leaky bucket) درخواست‌ها را با نرخ ثابت پردازش می‌کند. دو تنظیم لازم دارید:

  1. limit_req_zone در بخش http که حافظه و نرخ را تعریف می‌کند.
  2. limit_req در server یا location که منطقه را اعمال می‌کند.
http {
    limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
    limit_req_status 429;
}

معنی:

  • $binary_remote_addr: کلید محدودیت، یعنی آدرس IP کلاینت (فرم فشرده).
  • zone=general:10m: نام منطقه و 10 مگابایت حافظه؛ حدود 160 هزار آدرس را نگه می‌دارد.
  • rate=10r/s: ده درخواست در ثانیه. 5r/m یعنی پنج درخواست در دقیقه.
  • limit_req_status 429: کد پاسخ هنگام رد درخواست (پیش‌فرض 503 است).

محدود کردن درخواست در Nginx برای ورود وردپرس

صفحه ورود هدف اصلی حدس رمز است:

server {
    listen 443 ssl;
    server_name example.com;

    location = /wp-login.php {
        limit_req zone=login burst=3 nodelay;
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location / {
        limit_req zone=general burst=20 nodelay;
        try_files $uri $uri/ /index.php?$args;
    }
}

مسیر سوکت PHP و نسخه نمونه است. دو گزینه مهم دیگر:

  • burst=3: اجازه می‌دهد تا سه درخواست اضافه در صف بیایند، تا ترافیک عادی که کمی تند است رد نشود.
  • nodelay: درخواست‌های burst را بدون تأخیر پردازش می‌کند و فقط بعد از پر شدن آن رد می‌کند. بدون آن، درخواست‌ها با تأخیر و با همان نرخ پردازش می‌شوند.

limit_conn: محدود کردن اتصال هم‌زمان

برای جلوگیری از اینکه یک IP تعداد زیادی اتصال هم‌زمان بسازد (مثلاً دانلود موازی یا حمله ساده):

http {
    limit_conn_zone $binary_remote_addr zone=perip:10m;
}

server {
    limit_conn perip 20;
}

عدد را متناسب با کاربرد بگذارید. پشت NAT سازمانی، چند کاربر یک IP مشترک دارند و عدد خیلی کم آن‌ها را مسدود می‌کند.

آدرس واقعی پشت Cloudflare یا پراکسی

اگر سایت پشت Cloudflare یا یک پراکسی است، $remote_addr آدرس آن‌هاست و همه کاربران یک «IP» دارند. باید آدرس واقعی را با ماژول realip بگیرید:

set_real_ip_from 173.245.48.0/20;
real_ip_header CF-Connecting-IP;

فهرست کامل آدرس‌های Cloudflare را از سایت رسمی بردارید و همه را بنویسید. بدون این تنظیم، یک مهاجم باعث محدود شدن همه کاربران می‌شود. راه‌اندازی Cloudflare در Reverse Proxy چیست هم از دید پراکسی بررسی شده است.

استثنا برای آدرس‌های مجاز

برای دفتر یا سرویس پایش که نباید محدود شود، با geo و map کلید را خالی کنید (کلید خالی محدود نمی‌شود):

geo $limit {
    default 1;
    203.0.113.0/24 0;
}
map $limit $limit_key {
    0 "";
    1 $binary_remote_addr;
}
limit_req_zone $limit_key zone=general:10m rate=10r/s;

آدرس نمونه است. با این روش، آدرس‌های لیست مجاز در محدودیت نمی‌افتند.

آزمایش محدود کردن درخواست در Nginx

بعد از تنظیم، همیشه آزمایش و بارگذاری:

sudo nginx -t
sudo systemctl reload nginx

برای دیدن اثر، از یک ترمینال درخواست‌های پشت‌سرهم بفرستید:

for i in $(seq 1 15); do curl -s -o /dev/null -w "%{http_code}\n" https://example.com/wp-login.php; done

بعد از چند درخواست باید 429 ببینید. در error.log هم پیام‌هایی مثل limiting requests, excess: 3.5 ثبت می‌شود. برای خارج نکردن ربات گوگل از محدودیت، نرخ را برای مسیرهای عمومی بالا بگذارید؛ ربات‌های معتبر با رد شدن مکرر، خزش را کم می‌کنند.

نرخ مناسب چقدر است؟

عدد دقیقی برای همه سایت‌ها وجود ندارد، ولی راهنمای معقول:

مسیرنرخ پیشنهادی شروع
صفحه ورود (wp-login.php)5 درخواست در دقیقه، burst پایین
xmlrpc.phpاگر لازم نیست، کاملاً ببندید
API عمومیبر اساس مصرف واقعی، مثلاً 10 درخواست در ثانیه
کل سایت10 تا 30 درخواست در ثانیه برای هر IP با burst

بعد از چند روز لاگ را بررسی کنید و ببینید چقدر 429 تولید شده؛ اگر کاربر عادی رد می‌شود، نرخ را بالا ببرید.

خطاهای رایج

نشانهعلت و راه حل
همه کاربران 429 می‌گیرندآدرس واقعی گرفته نمی‌شود (پشت CDN)؛ realip را تنظیم کنید
limit_req_zone خطای «not allowed here»فقط در بخش http مجاز است و داخل server خطا می‌دهد
محدودیت اثر نداردمنطقه تعریف شده ولی limit_req در location درست قرار نگرفته
کاربران عادی رد می‌شوندburst کم است یا نرخ پایین
حافظه منطقه پر شدzone را بزرگ‌تر کنید (پیام could not allocate node در لاگ)
پاسخ 503 به‌جای 429limit_req_status 429 تنظیم نشده

سوالات متداول

آیا این محدودیت جای Fail2ban را می‌گیرد؟

نه. محدودیت درخواست فشار لحظه‌ای را کم می‌کند. Fail2ban آدرس‌های مهاجم را بر اساس لاگ برای مدت طولانی‌تری مسدود می‌کند. مکمل هم‌اند.

آیا ربات‌های جست‌وجو را مسدود می‌کند؟

اگر نرخ خیلی پایین باشد، بله. نرخ مسیرهای عمومی را بالا بگذارید و فقط مسیرهای حساس (ورود، API) را محدود کنید.

فرق rate و burst چیست؟

rate نرخ دائمی مجاز است. burst تعداد درخواست اضافه‌ای است که برای نوسان کوتاه‌مدت در صف تحمل می‌شود.

روی Apache هم می‌شود؟

Apache برای این کار ماژول‌هایی مثل mod_evasive یا mod_qos دارد و روش آن فرق می‌کند.

منابع

پاسخی بگذارید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *