لارافيل, Api / 2024-09-16

التعامل مع Api في لارافيل - الجزء الخامس - ما هو Rate Limiting في لارافيل، وكيفية إستخدامة في حماية الموقع.

التعامل مع Api في لارافيل - الجزء الخامس - ما هو Rate Limiting في لارافيل، وكيفية إستخدامة في حماية الموقع.

2024-09-16 وقت القراءه : 4 دقائق

عند العمل على Laravel RESTful API، واحدة من الإمور التي يجب معرفتها والإهتمام بها هي Rate Limit، فما هي.

 

ما هي Rate Limiting.

هي ألية يوفرها إطار العمل لارافيل، من أجل تحديد عدد الطلبات للروابط، حيث تساعد في:

  • حجب البرمجيات الضارة Malicious bots التي تقوم بإرسال طلبات من خلال API.
  • الحد من هجمات DOS Attack.
  • الحد من هجمات Brute Force.
  • تقليل التكلفة.
  • بقاء السيرفر متاح للمستخدمين.

وبهذه الطريقة تبقى دائما واجهة API الخاصه بنا، متاحة للمستخدمين الحقيقيين.

 

للتوضيح أكثر

لفرض أن لدينا هذا الرابط http://www.test.test/api/v2/brands وتتم زيارته (طلبه)، ألاف المرات في نفس الثانية من قبل نفس المستخدم، فإذا كانت موارد السيرفر لا تتحمل ذلك فإن الموقع لن يستجيب له مما يعني تعطيل الموقع عن جميع المستخدمين.

 

فيمكن تعريف Rate Limiting بأنها تقنية يمكن من خلالها التحكم في إستهلاك الموارد من خلال تحديد عدد الطلبات لكل مستخدم.

 

كيف يمكن لمستخدمي إطار العمل لارافيل إستخدام Rate Limiting؟

وفر إطار العمل لارافيل middleware إفتراضي باسم throttle حيث يمكننا من:

حماية التطبيق بشكل كامل

للقيام بذلك يمكننا الذهاب إلى app/http/kernel.php وتعديل middlewaregroups->api من 

'api' => [
    'throttle:api',
     \Illuminate\Routing\Middleware\SubstituteBindings::class,
],

إلى 

'api' => [
    'throttle:60,1',
     \Illuminate\Routing\Middleware\SubstituteBindings::class,
],

 

كما نلاحظ أنه تم تعديل throttle بـ throttle:2,1 لكن ماذا تعني throttle:2,1 ؟ تعني أنه يسمح بأن يتم الطلب مرتين في كل ثانية، فلو كانت throttle:10,1 فذلك يعني أنه يسمح بالطلب 10 مرات في كل ثانية.

 

في حال أنه تم طلب الرابط للمرة الثالثة فإننا سوف نحصل على الخطأ التالي

429 | TOO MANY REQUESTS

 

حماية routes معينة. 

إذا كنا لا نريد تطبيق Rate Limiting على جميع التطبيق، وأن يتم تطبيقة على routes معينة، بالإمكان إنشاء group في ملف api.php أو routes.php

Route::group(['middleware'=>'throttle:2,1'],function (){
     Route::apiResource('brands',BrandController::class);
});

 

إنشاء Rate Limiting مخصص

لو ذهبنا للملف RouteServiceProvider نجد الدالة configureRateLimiting ، نجد بها rate limiter باسم api

protected function configureRateLimiting()
{
    RateLimiter::for('api', function (Request $request) {
        return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());
    });
}

 

حيث تسمح هذه الدالة بـ 60 طلب بالدقيقة وذلك بالإعتماد على user->id إذا كان مسجل دخول أو request->ip إذا لم يكن المستخدم مسجل دخول.

ولإستخدام هذه الدالة، يجب تطبيقها على routes

Route::middleware(['throttle:api'])->group(function () {
     Route::apiResource('brands', BrandController::class);
});


مثال أخر على تطبيق rate limiting بحيث يسمح بمائة طلب للمستخدمين المسجلين، ومائة طلب بإستخدام ip للـ guests.

هنا سأقوم بإنشاء middleware جديد بإسم uploads في داخل الدالة configureRateLimiting في الملف RouteServiceProvider

protected function configureRateLimiting()
{
    RateLimiter::for('api', function (Request $request) {
        return Limit::perMinute(2)->by(optional($request->user())->id ?: $request->ip());
    });

    RateLimiter::for('uploads', function (Request $request) {
        return $request->user()
            ? Limit::perMinute(100)->by($request->user()->id)
            : Limit::perMinute(10)->by($request->ip());
    });
}

ولتطبيق uploads middleware الذي قمنا بإنشاؤه

Route::middleware(['throttle:uploads'])->group(function () {
     Route::apiResource('brands', BrandController::class);
});

كما نلاحظ أنه يمكن تطبيق Rate Limiting على الروابط، فورم تسجيل الدخول، فورم إدخال البيانات، رفع الملفات .... وذلك من خلال middleware=>throttling.

 

إنشاء رسالة خطأ مخصصة.

كما نعلم أنه في حال زيادة عدد الطلبات عن الحد المسموح به فإنه سيتم إرجاع الخطأ 429 | TOO MANY REQUESTS ، لكن ماذا لو أردنا إرجاع رسالة خطأ مخصصة.

إنشاء throttle باسم global

protected function configureRateLimiting()
{
    RateLimiter::for('api', function (Request $request) {
        return Limit::perMinute(2)->by(optional($request->user())->id ?: $request->ip());
    });
 
    RateLimiter::for('global', function (Request $request) {
        return Limit::perMinute(2)->response(function () {
            return response('Custom response...', 429);
        });
    });
}

تطبيق هذا throttle على route

Route::middleware(['throttle:global'])->group(function () {
    Route::apiResource('brands', BrandController::class);
});

هنا الأن في حالة زيادة عدد الطلبات عن 2 سيتم إرجاع الرسالة Custome response مع status code = 429

 


التعليقات
Nane
منذ سنتين

awesome!

إضافة تعليق
Loading...