هنگام توسعه یک وبسایت یا REST API با Laravel، یکی از موضوعات مهم امنیت و پایداری برنامه، کنترل تعداد درخواستهایی است که کاربران در یک بازه زمانی ارسال میکنند. اگر یک کاربر یا نرمافزار بتواند بدون محدودیت به یک مسیر درخواست بفرستد، ممکن است منابع سرور بیش از حد مصرف شوند یا سرویس در معرض حملات و استفاده نادرست قرار بگیرد.
برای مدیریت این شرایط، لاراول قابلیتی به نام Rate Limiting در اختیار توسعهدهندگان قرار میدهد. با استفاده از این قابلیت میتوان مشخص کرد هر کاربر، IP یا کلید شناساییشده، در یک بازه زمانی چند درخواست مجاز دارد.
در این مقاله یاد میگیریم Rate Limiting چیست، چگونه آن را در Laravel پیکربندی کنیم، چطور برای API محدودیت اختصاصی بسازیم، چگونه درخواستهای کاربران واردشده را از کاربران ناشناس جدا کنیم و در صورت عبور از محدودیت، پاسخ مناسب برگردانیم.
Rate Limiting چیست؟
Rate Limiting به معنای محدود کردن تعداد درخواستهایی است که یک کاربر یا منبع مشخص میتواند در مدتزمان معینی ارسال کند.
برای مثال، فرض کنید یک API برای جستوجوی محصولات دارید. اگر هر کاربر بتواند در هر دقیقه هزاران درخواست جستوجو ارسال کند، ممکن است پردازش درخواستها فشار زیادی به سرور و دیتابیس وارد کند.
با استفاده از Rate Limiting میتوانید قانونی مانند موارد زیر تعریف کنید:
- هر کاربر در هر دقیقه حداکثر ۶۰ درخواست ارسال کند.
- هر IP در هر دقیقه حداکثر ۳۰ بار درخواست ورود بفرستد.
- هر کاربر در هر دقیقه حداکثر ۱۰ درخواست جستوجوی سنگین داشته باشد.
- هر API عمومی محدودیت مشخصی برای تعداد درخواستها داشته باشد.
وقتی تعداد درخواستهای یک کلید شناسایی از حد تعیینشده عبور کند، لاراول میتواند درخواستهای بعدی را تا زمانی که محدودیت دوباره اجازه بدهد، رد کند.
Rate Limiting برای کنترل مصرف منابع و کاهش سوءاستفاده مفید است؛ اما بهتنهایی جایگزین احراز هویت، مجوز دسترسی، محافظت در برابر حملات توزیعشده یا زیرساخت مقابله با DDoS نیست.
چرا استفاده از Rate Limiting در Laravel اهمیت دارد؟
استفاده از محدودیت درخواستها در پروژههای واقعی چند مزیت مهم دارد.
۱. کاهش احتمال سوءاستفاده از API
اگر یک API عمومی بدون محدودیت باشد، ممکن است اسکریپتها یا کلاینتهای پرمصرف تعداد زیادی درخواست ارسال کنند. Rate Limiting میتواند تعداد درخواستهای مجاز را کنترل کند.
۲. محافظت از منابع سرور
برخی عملیات مانند جستوجوی پیچیده، تولید گزارش، ارسال پیامک و محاسبات سنگین به منابع بیشتری نیاز دارند. محدود کردن دفعات اجرای آنها میتواند به کنترل مصرف منابع کمک کند.
۳. کاهش فشار روی دیتابیس
اگر یک مسیر در هر درخواست چند Query سنگین اجرا کند، افزایش تعداد درخواستها میتواند عملکرد دیتابیس را تحت تأثیر قرار دهد. محدودسازی درخواستها یکی از راهکارهای کنترل این فشار است.
۴. محافظت بیشتر از مسیرهای حساس
مسیرهایی مانند ورود، ارسال کد تأیید، بازیابی رمز عبور و درخواست پیامک بهتر است محدودیتهای اختصاصی داشته باشند تا امکان ارسال انبوه درخواستها کاهش پیدا کند.
۵. کنترل مصرف سرویسهای خارجی
اگر API شما برای هر درخواست از یک سرویس خارجی استفاده کند، محدودسازی میتواند به کنترل تعداد فراخوانیها و هزینههای احتمالی کمک کند.
Rate Limiting در Laravel چگونه کار میکند؟
لاراول ابزارهایی برای تعریف محدودیتها و شمارش درخواستها دارد. یکی از کلاسهای اصلی این بخش RateLimiter است.
معمولاً ابتدا محدودیت را تعریف میکنیم و سپس آن را به مسیر یا گروهی از Routeها متصل میکنیم.
برای مثال، میتوانیم محدودیتی تعریف کنیم که هر کلید شناسایی در هر دقیقه حداکثر ۶۰ درخواست داشته باشد.
در بسیاری از پروژهها، محدودیتها از طریق Middleware اعمال میشوند. Middleware درخواست را پیش از رسیدن به Controller بررسی میکند و اگر محدودیت نقض شده باشد، میتواند درخواست را متوقف کند.
در لاراول، دو ابزار مهم در این بخش عبارتاند از:
RateLimiter: برای تعریف و مدیریت محدودیتهای درخواستthrottle: Middleware برای اعمال محدودیت روی درخواستها
مرحله اول: آشنایی با Middleware مربوط به Throttle
لاراول Middlewareای با نام throttle دارد که برای محدود کردن تعداد درخواستها استفاده میشود.
برای مثال، میتوانید یک Route را به این شکل تعریف کنید:
use Illuminate\Support\Facades\Route;
Route::get('/reports', function () {
return response()->json([
'message' => 'Report generated successfully',
]);
})->middleware('throttle:10,1');
در این مثال، محدودیت بهصورت ۱۰ درخواست در هر یک دقیقه تعریف شده است.
ساختار کلی این دستور به شکل زیر است:
->middleware('throttle:تعداد,دقیقه')
برای مثال:
| تنظیم | مفهوم |
|---|---|
throttle:10,1 | ۱۰ درخواست در هر دقیقه |
throttle:30,1 | ۳۰ درخواست در هر دقیقه |
throttle:100,1 | ۱۰۰ درخواست در هر دقیقه |
throttle:5,1 | ۵ درخواست در هر دقیقه |
این اعداد نمونه هستند و باید براساس نیاز واقعی برنامه انتخاب شوند.
نکته مهم این است که محدودیتهای ساده Middleware برای بسیاری از مسیرها مناسباند؛ اما زمانی که به تفکیک کاربران، IPها، نوع درخواست یا سیاستهای متفاوت نیاز داشته باشید، تعریف Rate Limiter اختصاصی انعطاف بیشتری ایجاد میکند.
مرحله دوم: تعریف Rate Limiter اختصاصی در Laravel
فرض کنید میخواهیم یک محدودیت مشخص برای API محصولات ایجاد کنیم.
در نسخههای جدید لاراول، میتوانیم محدودیتهای نامگذاریشده را در متد boot کلاس App\Providers\AppServiceProvider تعریف کنیم.
فایل زیر را باز کنید:
app/Providers/AppServiceProvider.php
سپس کد مربوط به Rate Limiter را اضافه کنید:
<?php
namespace App\Providers;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
//
}
public function boot(): void
{
RateLimiter::for('products', function (Request $request) {
return Limit::perMinute(60)
->by($request->user()?->id ?: $request->ip());
});
}
}
در این مثال، یک محدودیت با نام products تعریف کردهایم.
بیایید بخشهای مهم کد را بررسی کنیم.
متد RateLimiter::for
این متد برای تعریف یک Rate Limiter نامگذاریشده استفاده میشود:
RateLimiter::for('products', function (Request $request) {
// Define the limit
});
نام products شناسه این محدودیت است. بعداً از همین نام برای اتصال آن به Route استفاده میکنیم.
متد Limit::perMinute
این متد تعداد درخواستهای مجاز در هر دقیقه را مشخص میکند:
Limit::perMinute(60)
در این مثال، مقدار محدودیت ۶۰ درخواست در دقیقه است.
متد by
این متد کلیدی را مشخص میکند که محدودیت براساس آن محاسبه میشود:
->by($request->user()?->id ?: $request->ip())
اگر کاربر وارد حساب خود شده باشد، شناسه او مبنای محدودیت قرار میگیرد. در غیر این صورت، IP درخواست استفاده میشود.
این روش برای بسیاری از APIها نقطه شروع مناسبی است؛ بااینحال، اگر احراز هویت، چند نوع کلاینت یا معماری پراکسی داشته باشید، ممکن است لازم باشد کلید محدودیت را متناسب با شرایط پروژه طراحی کنید.
مرحله سوم: اتصال Rate Limiter به Route
حالا که محدودیت products را تعریف کردهایم، میتوانیم آن را به Route متصل کنیم.
برای مثال، در فایل routes/api.php بنویسید:
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Api\ProductController;
Route::get('/products', [
ProductController::class,
'index',
])->middleware('throttle:products');
با این تنظیم، درخواستهای ارسالی به مسیر زیر تحت محدودیت products قرار میگیرند:
GET /api/products
پیشوند /api در ساختار رایج مسیرهای API لاراول بهصورت خودکار اضافه میشود.
اکنون اگر کلید شناسایی موردنظر بیش از ۶۰ درخواست در بازه تعیینشده ارسال کند، درخواستهای اضافی ممکن است با پاسخ 429 Too Many Requests رد شوند.
اگر میخواهید چند Route را تحت یک محدودیت قرار دهید، میتوانید از گروه Middleware استفاده کنید:
Route::middleware('throttle:products')->group(function () {
Route::get('/products', [
ProductController::class,
'index',
]);
Route::get('/categories', function () {
return response()->json([
'data' => [],
]);
});
});
در این حالت، هر دو مسیر از همان Rate Limiter استفاده میکنند. رفتار دقیق شمارش درخواستها به کلیدی که در Rate Limiter تعریف کردهاید وابسته است؛ بنابراین اگر هر دو مسیر از یک کلید استفاده کنند، درخواستهای آنها میتوانند در یک محدودیت مشترک محاسبه شوند.
مرحله چهارم: تعیین محدودیت متفاوت برای کاربران واردشده و مهمانها
در بعضی پروژهها، کاربران واردشده و کاربران ناشناس نباید محدودیت یکسانی داشته باشند.
برای مثال، ممکن است بخواهید کاربران واردشده در هر دقیقه ۱۰۰ درخواست و کاربران ناشناس فقط ۲۰ درخواست مجاز داشته باشند.
میتوانیم Rate Limiter را به شکل زیر تعریف کنیم:
RateLimiter::for('api-custom', function (Request $request) {
if ($request->user()) {
return Limit::perMinute(100)
->by('user:' . $request->user()->id);
}
return Limit::perMinute(20)
->by('ip:' . $request->ip());
});
در این مثال:
- برای کاربران واردشده، شناسه کاربر کلید محدودیت است.
- برای کاربران ناشناس، IP درخواست کلید محدودیت است.
- پیشوندهای
user:وip:کمک میکنند کلیدهای این دو گروه با یکدیگر اشتباه نشوند.
اکنون میتوانیم این محدودیت را به Route موردنظر متصل کنیم:
Route::get('/products', [
ProductController::class,
'index',
])->middleware('throttle:api-custom');
این روش برای APIهایی مفید است که کاربران ثبتنامشده و کاربران عمومی از آنها استفاده میکنند.
نکته: محدودیت بالاتر برای کاربران واردشده به معنای قابلاعتماد بودن کامل آنها نیست. حتی کاربران احراز هویتشده نیز ممکن است درخواستهای غیرعادی ارسال کنند؛ بنابراین محدودیتها را براساس رفتار مورد انتظار سرویس تعیین کنید.
مرحله پنجم: تعریف محدودیت بر اساس نوع عملیات
همه Routeها به منابع یکسانی نیاز ندارند. برای مثال، دریافت فهرست محصولات معمولاً ارزانتر از تولید یک گزارش سنگین است.
به همین دلیل، بهتر است برای عملیات مختلف محدودیتهای متفاوت تعریف کنید.
فرض کنید دو محدودیت داریم:
RateLimiter::for('product-list', function (Request $request) {
return Limit::perMinute(100)
->by($request->user()?->id ?: $request->ip());
});
RateLimiter::for('heavy-report', function (Request $request) {
return Limit::perMinute(5)
->by($request->user()?->id ?: $request->ip());
});
حالا هرکدام را به مسیر مناسب وصل میکنیم:
Route::get('/products', [
ProductController::class,
'index',
])->middleware('throttle:product-list');
Route::get('/reports/heavy', function () {
return response()->json([
'message' => 'Report generated',
]);
})->middleware('throttle:heavy-report');
در این مثال، دریافت محصولات محدودیت بیشتری دارد؛ اما مسیر گزارش سنگین فقط پنج درخواست در دقیقه میپذیرد.
محدودیت واقعی باید با توجه به هزینه اجرای درخواست، ظرفیت سرور، تعداد کاربران و تجربه کاربری تعیین شود.
مرحله ششم: محدود کردن درخواستهای ورود به حساب کاربری
یکی از مهمترین کاربردهای Rate Limiting، محافظت از مسیرهای حساس مانند ورود به حساب کاربری است.
فرض کنید مسیر ورود شما در یک Controller تعریف شده است:
Route::post('/login', [
AuthController::class,
'login',
]);
میتوانیم برای آن Rate Limiter اختصاصی بسازیم:
RateLimiter::for('login', function (Request $request) {
$email = strtolower((string) $request->input('email'));
return Limit::perMinute(5)
->by($email . '|' . $request->ip());
});
سپس آن را به مسیر ورود متصل کنیم:
Route::post('/login', [
AuthController::class,
'login',
])->middleware('throttle:login');
در این مثال، محدودیت براساس ترکیبی از ایمیل واردشده و IP محاسبه میشود.
این کار میتواند تعداد تلاشهای تکراری برای یک حساب از یک IP مشخص را محدود کند. بااینحال، برای محافظت بهتر در برابر حملات حدس رمز عبور، لازم است سایر کنترلهای امنیتی نیز در نظر گرفته شوند؛ زیرا مهاجم ممکن است از IPهای مختلف یا نامهای کاربری متعدد استفاده کند.
همچنین Rate Limiting نباید به شکلی طراحی شود که مهاجم بتواند بهراحتی با ارسال درخواستهای عمدی، دسترسی کاربران واقعی به حسابهایشان را مختل کند.
مرحله هفتم: محدود کردن درخواست ارسال پیامک و کد تأیید
در سامانههایی که از کد یکبارمصرف یا OTP استفاده میکنند، محدودسازی درخواستها اهمیت زیادی دارد.
برای مثال، اگر کاربر بتواند در هر ثانیه چندین درخواست ارسال کد تأیید ثبت کند، ممکن است هزینه پیامک افزایش پیدا کند یا از سرویس برای ارسال پیامهای ناخواسته سوءاستفاده شود.
یک Rate Limiter ساده میتواند به شکل زیر باشد:
RateLimiter::for('send-otp', function (Request $request) {
$phone = (string) $request->input('phone');
return Limit::perMinute(3)
->by($phone . '|' . $request->ip());
});
سپس آن را روی Route ارسال کد قرار میدهیم:
Route::post('/send-otp', [
OtpController::class,
'send',
])->middleware('throttle:send-otp');
این کد نمونهای اولیه است و برای استفاده عملیاتی باید شماره تلفن نیز پیش از استفاده بهدرستی اعتبارسنجی و نرمالسازی شود.
برای یک سامانه OTP امن، معمولاً باید چند محدودیت مستقل در نظر گرفته شود؛ از جمله:
- تعداد درخواست برای هر شماره تلفن
- تعداد درخواست از هر IP
- فاصله زمانی بین ارسال مجدد کد
- تعداد تلاشهای وارد کردن کد
- مدت اعتبار کد
- محدودیتهای هزینه و تعداد ارسال در سطح سرویس پیامک
Rate Limiting فقط بخشی از راهکار امنیتی است و نباید بهتنهایی برای محافظت از سامانه احراز هویت استفاده شود.
مرحله هشتم: مدیریت پاسخ خطای 429
زمانی که تعداد درخواستها از حد مجاز عبور میکند، پاسخ استاندارد HTTP برای این وضعیت 429 Too Many Requests است.
در بسیاری از موارد، Middleware مربوط به Throttle این پاسخ را بهصورت خودکار برمیگرداند.
اما اگر بخواهیم پاسخ JSON سفارشی داشته باشیم، میتوانیم از قابلیت response در کلاس Limit استفاده کنیم:
RateLimiter::for('products', function (Request $request) {
return Limit::perMinute(60)
->by($request->user()?->id ?: $request->ip())
->response(function (Request $request, array $headers) {
return response()->json([
'message' => 'تعداد درخواستهای شما بیش از حد مجاز است.',
'error' => 'too_many_requests',
], 429, $headers);
});
});
در این مثال، اگر محدودیت نقض شود، پاسخ JSON همراه با کد وضعیت 429 برگردانده میشود.
نمونه پاسخ:
{
"message": "تعداد درخواستهای شما بیش از حد مجاز است.",
"error": "too_many_requests"
}
هدرهای مربوط به محدودیت نیز به پاسخ اضافه میشوند تا کلاینت بتواند در صورت پشتیبانی، اطلاعاتی درباره محدودیت درخواستها دریافت کند.
در طراحی API بهتر است پیام خطا روشن باشد و اطلاعات داخلی سرور را افشا نکند.
مرحله نهم: استفاده از Rate Limiting برای کل گروه API
گاهی میخواهیم بهجای تعریف محدودیت جداگانه برای هر Route، یک محدودیت عمومی برای گروهی از APIها داشته باشیم.
برای مثال، میتوانیم یک Rate Limiter با نام public-api تعریف کنیم:
RateLimiter::for('public-api', function (Request $request) {
return Limit::perMinute(60)
->by($request->user()?->id ?: $request->ip());
});
سپس آن را به گروهی از مسیرها متصل کنیم:
Route::middleware('throttle:public-api')->group(function () {
Route::get('/products', [
ProductController::class,
'index',
]);
Route::get('/categories', [
CategoryController::class,
'index',
]);
});
در این حالت، درخواستهای این مسیرها میتوانند از یک سهمیه مشترک استفاده کنند، زیرا هر دو از یک Rate Limiter و یک کلید شناسایی بهره میبرند.
اگر میخواهید هر مسیر سهمیه مستقل داشته باشد، باید کلید محدودیت یا Rate Limiterهای متفاوتی طراحی کنید.
نکته مهم درباره گروه API پیشفرض: در برخی ساختارهای لاراول، گروه API ممکن است از قبل Middleware محدودسازی داشته باشد. پیش از افزودن محدودیت جدید، تنظیمات گروه API و مسیرهای موجود را بررسی کنید تا محدودیتها ناخواسته روی هم قرار نگیرند.
مرحله دهم: محدودیتهای چندگانه برای یک Route
در برخی سرویسها، یک محدودیت بهتنهایی کافی نیست. برای مثال، ممکن است بخواهید هم تعداد درخواستهای هر دقیقه را کنترل کنید و هم تعداد درخواستهای روزانه را محدود نگه دارید.
لاراول امکان تعریف چند Limit در یک Rate Limiter را فراهم میکند:
RateLimiter::for('reports', function (Request $request) {
$key = $request->user()?->id ?: $request->ip();
return [
Limit::perMinute(10)->by('minute:' . $key),
Limit::perDay(200)->by('day:' . $key),
];
});
اکنون میتوان این محدودیت را به مسیر گزارشها متصل کرد:
Route::get('/reports', [
ReportController::class,
'index',
])->middleware('throttle:reports');
در این مثال، هر کلید شناسایی حداکثر ۱۰ درخواست در دقیقه و ۲۰۰ درخواست در روز خواهد داشت.
استفاده از چند Limit برای سرویسهایی مانند تولید گزارش، پردازش فایل، جستوجوی پیشرفته و APIهای دارای سهمیه مصرف میتواند مفید باشد.
البته محدودیتهای روزانه و سیاستهای سهمیهبندی بلندمدت باید با نیاز کسبوکار و روش ذخیرهسازی شمارندهها هماهنگ باشند.
مرحله یازدهم: Rate Limiting و Cache در Laravel
برای مدیریت محدودیتها، لاراول از زیرساخت ذخیرهسازی شمارندهها استفاده میکند. بسته به پیکربندی برنامه، این اطلاعات میتوانند در Cache ذخیره شوند.
در پروژههای ساده ممکن است Cache فایل یا دیتابیس کافی باشد؛ اما در برنامههای پرترافیک یا پروژههایی که چند سرور دارند، انتخاب درایور مناسب اهمیت زیادی پیدا میکند.
برای مثال، Redis میتواند گزینه مناسبی برای نگهداری شمارندههای Rate Limiting در محیطهای پرترافیک باشد.
مزیت استفاده از یک Cache مشترک این است که اگر چند نمونه از برنامه روی سرورهای مختلف اجرا شوند، محدودیتها میتوانند از شمارندههای مشترک استفاده کنند؛ البته به شرطی که تمام نمونهها به همان زیرساخت Cache و پیکربندی سازگار متصل باشند.
اگر هر سرور شمارندههای مستقل داشته باشد، ممکن است کاربر بتواند با جابهجایی میان سرورها بیشتر از سهمیه مورد انتظار درخواست ارسال کند.
در پروژههای چندسروری، باید موارد زیر را بررسی کنید:
- همه سرورها از Cache مشترک استفاده میکنند یا خیر.
- تنظیمات Cache و کلیدهای محدودیت در همه سرورها یکسان هستند یا خیر.
- شمارندهها با چه مدتزمانی نگهداری میشوند.
- رفتار سیستم در صورت قطع شدن Cache چگونه خواهد بود.
- آیا ظرفیت Cache برای تعداد درخواستهای مورد انتظار کافی است یا خیر.
برای آشنایی بیشتر با این موضوع، مقاله آموزش Cache در Laravel و آموزش Redis در Laravel را مطالعه کنید.
مرحله دوازدهم: نکات مهم درباره IP و پراکسی
اگر برنامه Laravel پشت Reverse Proxy، Load Balancer یا سرویس واسط اجرا میشود، ممکن است IP مستقیمی که برنامه مشاهده میکند، متعلق به پراکسی باشد نه کاربر نهایی.
در چنین شرایطی، اگر تمام درخواستها با IP پراکسی شناسایی شوند، ممکن است کاربران مختلف در یک سهمیه مشترک قرار بگیرند.
از طرف دیگر، اعتماد نادرست به هدرهایی مانند X-Forwarded-For میتواند باعث شود کاربر مقدار IP را جعل کند و محدودیت را دور بزند.
برای جلوگیری از این مشکل:
- تنظیمات Trusted Proxies را متناسب با زیرساخت واقعی پروژه انجام دهید.
- فقط به پراکسیهایی اعتماد کنید که تحت کنترل شما هستند یا بهدرستی مورد اعتماد قرار گرفتهاند.
- مطمئن شوید لاراول IP واقعی درخواست را با تنظیمات معتبر تشخیص میدهد.
- در صورت وجود احراز هویت، برای عملیات حساس از شناسه کاربر بهعنوان یکی از کلیدهای محدودیت استفاده کنید.
- برای سرویسهای عمومی، محدودیتهای مکمل و کنترل سوءاستفاده را در نظر بگیرید.
همچنین به خاطر داشته باشید که IP همیشه معادل یک کاربر نیست؛ چند کاربر ممکن است از یک شبکه یا IP مشترک استفاده کنند و یک کاربر نیز ممکن است در طول زمان IP متفاوتی داشته باشد.
مرحله سیزدهم: آزمایش Rate Limiting
پس از تعریف Rate Limiter، باید مطمئن شویم محدودیت بهدرستی اعمال میشود.
فرض کنید Rate Limiter شما حداکثر پنج درخواست در دقیقه را مجاز میداند.
میتوانید با Postman یا cURL چند درخواست پشت سر هم ارسال کنید و پاسخها را بررسی کنید.
برای مثال، اگر مسیر زیر را دارید:
GET /api/products
آن را چندین بار در بازه کوتاه فراخوانی کنید.
در درخواستهایی که در محدوده مجاز قرار دارند، باید پاسخ معمول API دریافت شود. پس از عبور از محدودیت، انتظار میرود پاسخ 429 Too Many Requests برگردد.
برای بررسی دقیقتر، موارد زیر را آزمایش کنید:
- آیا محدودیت برای کاربر واردشده و مهمان متفاوت است؟
- آیا دو کاربر با شناسههای متفاوت سهمیه جداگانه دارند؟
- آیا درخواستهای چند Route بهصورت مشترک شمرده میشوند؟
- آیا پس از پایان بازه محدودیت، درخواستها دوباره پذیرفته میشوند؟
- آیا هدرهای مرتبط با محدودیت در پاسخ وجود دارند؟
- آیا تنظیمات پراکسی باعث شناسایی اشتباه IP شدهاند؟
برای تستهای خودکار، میتوانید رفتار محدودیت را با درخواستهای متعدد در Feature Test بررسی کنید. بهتر است تستها از Cache یا شمارندههای باقیمانده از تستهای قبلی مستقل باشند.
تفاوت Rate Limiting با Authentication و Authorization
این سه مفهوم با یکدیگر متفاوتاند و نباید جایگزین یکدیگر در نظر گرفته شوند.
| مفهوم | کاربرد |
|---|---|
| Authentication | مشخص میکند کاربر چه کسی است |
| Authorization | مشخص میکند کاربر اجازه انجام چه عملی را دارد |
| Rate Limiting | تعداد درخواستهای مجاز در یک بازه زمانی را کنترل میکند |
برای مثال، کاربر ممکن است احراز هویت شده باشد، اما اجازه حذف محصول را نداشته باشد. همچنین ممکن است اجازه مشاهده محصولات را داشته باشد، ولی در یک دقیقه فقط تعداد مشخصی درخواست بتواند ارسال کند.
بنابراین، در طراحی API امن باید این کنترلها را در کنار یکدیگر استفاده کنید.
برای ادامه یادگیری، مقالههای Authentication در Laravel، Authorization در Laravel و Laravel Sanctum را نیز مطالعه کنید.
بهترین روشها برای استفاده از Rate Limiting در Laravel
برای اینکه محدودسازی درخواستها در پروژه واقعی مؤثر باشد، نکات زیر را رعایت کنید.
محدودیتها را متناسب با نوع عملیات تعیین کنید
برای تمام Routeها یک عدد ثابت در نظر نگیرید. دریافت یک فهرست ساده معمولاً با تولید گزارش سنگین یا ارسال پیامک یکسان نیست.
برای مسیرهای حساس محدودیت اختصاصی بسازید
ورود، بازیابی رمز عبور، ارسال OTP، جستوجوی پرهزینه و عملیات مالی ممکن است به سیاستهای متفاوتی نیاز داشته باشند.
کلید محدودیت را با دقت انتخاب کنید
استفاده از IP برای همه سناریوها کافی نیست. در مسیرهای احراز هویتشده میتوانید از شناسه کاربر یا ترکیبی از شناسهها استفاده کنید.
محدودیت را در محیط واقعی آزمایش کنید
رفتار برنامه در محیط چندسروری، پشت پراکسی و با Cache مشترک ممکن است با محیط توسعه متفاوت باشد.
پاسخ خطای قابلفهم برگردانید
پاسخ 429 باید به کلاینت اعلام کند که محدودیت درخواست نقض شده است. در صورت نیاز میتوانید اطلاعات زمان انتظار را نیز در هدرهای مناسب ارائه کنید.
Rate Limiting را جایگزین امنیت کامل نکنید
محدودسازی تعداد درخواستها فقط یکی از لایههای محافظتی است. اعتبارسنجی، احراز هویت، مجوز دسترسی، ثبت رخدادهای امنیتی و محافظت زیرساختی همچنان اهمیت دارند.
سوالات متداول درباره Rate Limiting در Laravel
Rate Limiting در Laravel چیست؟
قابلیتی برای کنترل تعداد درخواستهایی است که یک کاربر، IP یا کلید شناساییشده میتواند در یک بازه زمانی ارسال کند. این قابلیت برای کنترل مصرف منابع و کاهش سوءاستفاده از API کاربرد دارد.
چگونه تعداد درخواستهای یک Route را محدود کنیم؟
میتوانید از Middleware زیر استفاده کنید:
Route::get('/reports', function () {
return response()->json([
'message' => 'OK',
]);
})->middleware('throttle:10,1');
این نمونه حداکثر ۱۰ درخواست در هر دقیقه را برای کلیدهای شمارششده توسط Middleware مجاز میکند.
خطای 429 در Laravel به چه معناست؟
کد HTTP 429 Too Many Requests به این معناست که درخواستهای ارسالشده از محدودیت تعیینشده عبور کردهاند.
آیا میتوان برای هر کاربر محدودیت جداگانه تعریف کرد؟
بله. با استفاده از RateLimiter::for و متد by میتوانید کلید محدودیت را براساس شناسه کاربر، IP یا ترکیبی از آنها تعریف کنید.
آیا Rate Limiting جلوی تمام حملات را میگیرد؟
خیر. این قابلیت به کنترل تعداد درخواستها کمک میکند، اما جایگزین فایروال، محافظت در برابر DDoS، احراز هویت یا سایر کنترلهای امنیتی نیست.
آیا Rate Limiting در پروژه چندسروری نیز کار میکند؟
بله، اما برای شمارش هماهنگ درخواستها باید پیکربندی Cache و کلیدهای محدودیت بین سرورها سازگار باشد. استفاده از Cache مشترکی مانند Redis میتواند به این هماهنگی کمک کند.
آیا میتوان برای ارسال پیامک محدودیت جداگانه تعیین کرد؟
بله. میتوانید یک Rate Limiter مستقل برای مسیر ارسال پیامک یا OTP تعریف کنید و محدودیت را براساس شماره تلفن، IP یا ترکیبی از آنها اعمال کنید.
جمعبندی
Rate Limiting یکی از ابزارهای مهم Laravel برای کنترل مصرف API و جلوگیری از ارسال بیش از حد درخواستها است. با تعریف محدودیتهای مناسب میتوانید تعداد درخواستهای کاربران را مدیریت کنید، از مسیرهای حساس محافظت بیشتری داشته باشید و فشار ناشی از درخواستهای پرتعداد را کاهش دهید.
در این مقاله، Middleware مربوط به Throttle، تعریف Rate Limiter اختصاصی، محدودیت براساس کاربر و IP، محافظت از مسیرهای ورود و ارسال OTP، پاسخ 429 و نقش Cache در پروژههای چندسروری را بررسی کردیم.
برای استفاده حرفهای از Rate Limiting، محدودیتها را متناسب با نوع عملیات و نیاز کسبوکار انتخاب کنید و آنها را در کنار احراز هویت، مجوز دسترسی و سایر کنترلهای امنیتی به کار ببرید.





