تحديد عناوين اي بي محدده يمكنها الاتصال مع Laravel API

من عرب اندكس

كتبه: Mohammed AlShannaq

اذا كنت تعمل على مشروع لارفال (Laravel) بحيث يقدم خدمة API ربما تحتاج في بعض الاحيان للسماح فقط لعناوين اي بي محدده باستخدام ال API. على الرغم من ان هذا الامر غير شائع الحدوث خصوصا لخدمات API العامة ولكن اذا كنت تطور API خاصا فربما تحتاج لادراج هذة الميزه في التطبيق لمزيد من الحماية. وهنا سوف اتحدث عن كيفية القيام بذلك.

أسباب تحديد عناوين الـ IP التي يمكنها الوصول إلى API Gateway المبرمجة بـ Laravel

الأمان:

  • حماية API من الهجمات: تقييد الوصول إلى API Gateway من خلال عناوين IP محددة يقلّل من خطر الهجمات الخبيثة، مثل هجمات DDoS أو اختراقات البيانات.
  • منع الوصول غير المصرح به: تحديد عناوين IP المسموح لها بالوصول إلى API Gateway يُتيح لك التحكم في من يمكنه استخدام API، ممّا يُحسّن من أمان البيانات والعمليات.

إدارة النطاق الترددي:

  • منع استنزاف النطاق الترددي: يمكنك تحديد عناوين IP المسموح لها بالوصول إلى API Gateway لمنع استنزاف النطاق الترددي من قبل مستخدمين غير مصرح لهم.
  • تحسين أداء API: تقييد الوصول إلى API Gateway يُتيح لك تحسين أداء API من خلال تقليل عدد الطلبات غير الضرورية التي تاتي من جهات غير مصرح لها.

أمثلة على سيناريوهات قد تتطلب تحديد عناوين الـ IP:

  • API داخلي: إذا كان لديك API داخلي يستخدم من قبل موظفي الشركة فقط، يمكنك تحديد عناوين IP المسموح لها بالوصول إلى API Gateway لضمان الوصول من قبل موظفي الشركة فقط.
  • API تجاري: إذا كنت تقدم API تجاريًا لعملاء محددين، يمكنك تحديد عناوين IP المسموح لها بالوصول إلى API Gateway لضمان الوصول من قبل العملاء فقط. (من الامثله على ذلك API شركة ENOM حيث تقيد عناوين الاي بي المسموح لها).
  • API حساس: إذا كان لديك API حساس يتعامل مع بيانات حساسة، يمكنك تحديد عناوين IP المسموح لها بالوصول إلى API Gateway لضمان أمان البيانات.

ملاحظة:

  • تحديد عناوين IP ليس حلاً شاملا للأمان وليس بديلا ل API Token ابدا ، ويجب استخدامه مع ممارسات أمان أخرى مثل التشفير والمصادقة.
  • قد يكون تقييد الوصول إلى API Gateway غير عملي في بعض الحالات، مثل تطبيقات الهاتف المحمول التي تتصل بالإنترنت من خلال شبكات Wi-Fi مختلفة او لخدمات API العامة التي يستخدمها مستخدمين غير معروفين مسبقا.

تنفيذ عملية تحديد عناوين الاي بي المسموح لها الاتصال ب API

خطوات العمل: سوف نحتاج الخطوات التالية لتنفيذ هذا الموضوع:

  1. انشاء middleware جديد في لارفال.
  2. تحرير ال middleware الجديد ووضع الكود الصحيح للتحقق من عناوين الاي بي المسموح لها.
  3. تسجيل ال middleware الجديد في ملف Kernel.php ضمن routeMiddleware لضمان عمله.
  4. التعديل على routes ال API من اجل تنفيد ال middleware مع كل طلب يتم على ال API

1.انشاء middleware جديد في لارفال

في البداية تحتاج انشاء middleware ولنسميه مثلا IPAccessControl لهذا نقوم بتنفيد الامر التالي من اجل انشاء middleware جديد

php artisan make:middleware IPAccessControl

# هذا الامر سوف ينشئ الملف التالي
# app/Http/Middleware/IPAccessControl.php

2.تحرير ال middleware الجديد ووضع الكود الصحيح للتحقق من عناوين الاي بي المسموح لها.

والان سوف نقوم على تحرير الملف app/Http/Middleware/IPAccessControl.php ووضع الكود التالي بداخلة:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class IPAccessControl
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        $allowedIPs = ['192.168.1.100', '192.168.1.101']; // مثال للعناوين المسموح لها 

        if (!in_array($request->ip(), $allowedIPs)) {
            return response()->json([
                'message' => 'Unauthorized access: Your IP address is not permitted to use this API.',
                'status' => 403,
            ], 403);
        }

        return $next($request);
    }
}

لاحظ اننا في الكود السابق استخدمنا مصفوفه بعناوين الاي بي المسموح بها الوصول الي API وهذا الامر ليس الامر الامثل لان الافضل ان يتم اما تعريف قائمة الاي بي في قاعدة البيانات او من خلال ملف كونفيج منفصل. (ولكن لتبسيط المثال تم استخدام مصفوفه).

3. تسجيل ال middleware الجديد في ملف Kernel.php ضمن routeMiddleware لضمان عمله.

الخطوة التالية هو اننا يجب ان نقم بتسجيل ال middleware الذي قمنا بانشاءه بداخل HTTP Kernel الخاصه ب لارفال وذلك بتحرير الملف app/Http/Kernel.php والبحث عن تعريف ل $routeMiddleware واضافه الكود التالي

    // لاحظ انه في حال عدم وجود تعريف ل
    // $routeMiddleware
    // في الملف Kernel.php
    //قم على وضع التعريف كما هو بادناه
    //واذا كان موجودا فاضف ipcontol اليه
    /**
     * The route middleware registered in the application.
     *
     * @var array
     */
    protected $routeMiddleware = [
        'ipcontrol' => \App\Http\Middleware\IPAccessControl::class,
    ];

4. التعديل على routes ال API من اجل تنفيد ال middleware مع كل طلب يتم على ال API

الخطوة التالية هي اننا يجب ان نقوم بحماية ال API routes باستخدام ipcontrol middleware الذي قمنا بتعريفه اعلاه ٫ وذلك بتحرير الملف routes/api.php والتاكد من واضع ال middleware كما في المثال التالي:

Route::middleware('ipcontrol')->group(function () {
    // هنا تاتي روابط API التي تود حمايتها
});

لاحظ انه ربما يتم حمايه ال API ب API token فربما يكون محتوى الملف routes/api.php مختلف بمعنى انه يتم حماية روابط الوصول باكثر من middleware لهذا يجب التاكد من اضافه ipcontrol الى قائمة ال middlewares الموجودة ٫ مثال:

Route::middleware(['auth:sanctum', 'throttle:api', 'ipcontrol'])->group(function () {
   //هنا تاتي الروابط التي تود حمايتها
});

الان جرب الوصول الى احد روابط API من خلال Postman مثلا من اي بي غير مصرح له وسوف تجد رساله الخطا التالية (بكود 403)

{
    "message": "Unauthorized access: Your IP address is not permitted to use this API.",
    "status": 403
}

ولكن لو حاولت الوصول الى رابط API من خلال عنوان اي بي مصرح له (موجود في المصفوفه اعلاه) فانه سوف يتم تنفيذ الامر بشكل طبيعي.

وبهذا نكون قد قمنا بتحديد عناوين الاي بي التي يصرح لها الاتصال ب API بحيث انه يسمح لها فقط بالاتصال ب API اما غيرها من عناوين الاي بي فلا يسمح لها بالاتصال ب API Gateway حتى وان قامت بتزويد معلومات دخول (token) صحيحة.

لاحظ ان استخدام عناوين الاي بي في مصفوفه ضمن ال middleware لا يعتبر حلا امثلا لانه لو احتجنا ان نقوم باضافه عناوين اي بي جديده فيجب علينا التعديل على الكود البرمجي وهذا غير مستحسن و ولقد قمت على استخدام هذا الاسلوب فقط لغايات الشرح ٫ الان يمككنا تحسين الكود لجعله امثلا ٫ مثلا يمكننا تحديد ان تكون عناوين الاي بي مخزنه في قاعده البيانات لغايات التعديل عليها من خلال backend او يمكن مثلا استخدام ملف كونفج من اجل وضع قائمة عناوين الاي بي المسموح لها في ملف كونفيج منفصل ليتم اضافتها في ملف .env

تحسين عملية التحديد بجعل عناوين الاي بي المصرح لها في قاعدة البيانات بدلا من المصفوفة

كما تلاحظ في المثال السابق استخدمنا مصفوفة لتخزين عناوين الاي بي المصرح لها والتي كانت تحتوي علي البيانات التالية:

$allowedIPs = ['192.168.1.100', '192.168.1.101']; // مثال للعناوين المسموح لها

وهذا الامر ليس امرا مثاليا حيث انه من غير المعقول انه يجب علينا تحرير الكود البرمجي في كل مره نود اضافه عنوان اي بي جديد او التعديل على قائمة العناوين ٫ لهذا وللتخلص من هذه الاشكاليه فانه يمكن على سبيل المثال انشاء جدول في قاعدة البيانات من اجل وضع عناوين الاي بي المصرح لها في الجدول وجعل لارفال يقوم بفحص ذلك الجدول عند كل عملية طلب API للتحقق من ان عناوين الاي بي لصاحب الطلب مصرح له الاتصال او لا. ولاجراء هذا الامر فانه يجب علينا ما يلي:

  1. انشاء model جديده خاصه بعناوين الاي بي (جدول قاعدة البيانات)
  2. انشاء migration file يقوم بانشاء الجدول في قاعده البيانات وتطبيق ال migration على النظام.
  3. التعديل على الكود البرمجي لدالة middleware handle لتقوم بجلب عناوين الاي بي من قاعدة البيانات وفحصها بدلا من استخدام المصفوفة.

والتالية هو توضيح لذلك:

1. انشاء model جديده خاصه بعناوين الاي بي (جدول قاعدة البيانات)

لانشاء modle جديد في لارفال نقوم بتنفيذ الامر التالي:

php artisan make:model AllowedIp

هذا الامر سوف يقوم بانشاء الملف Models/AllowedIp.php

2. انشاء migration file يقوم بانشاء الجدول في قاعده البيانات وتطبيق ال migration على النظام.

لانشاء migration file من اجل انشاء جدول قاعدة البيانات نقوم بتنفيذ الامر التالي:

php artisan make:migration create_allowed_ips_table

هذا الامر سوف يقوم بانشاء ملف جديد داخل المجلد database/migrations باسم مشابه للملف التالي: 2024_04_01_213320_create_allowed_ips_table.php (يختلف اسم الملف باختلاف التاريخ) الان نقوم على تحرير ملف ال migrations الذي تم انشاءه (2024_04_01_213320_create_allowed_ips_table.php) والتاكد من ان محتواه كما يلي:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateAllowedIpsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('allowed_ips', function (Blueprint $table) {
            $table->id();
            $table->string('ip_address')->unique()->nullable(false);
            $table->string('notes', 200)->nullable(); //ايه ملاحظات مع الاي بي للتذكر
            $table->timestamps();

            $table->index('ip_address');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('allowed_ips');
    }
}

لاحظ ان جدول قاعدة البيانات سوف يكون بالاسم allowed_ips الان يجب علينا ان نقوم بتنطبيق ال migration file وذلك بتنفيذ الامر التالي:

php artisan migrate

الان قم على استخدام تطبيق ادارة قواعد البيانات المفضل لديك (مثلا phpMyAdmin) للوصول الى قاعدة البيانات الخاصة بك ومن ثم ابحث عن الجدول allowed_ips وقم بادخال عناوين الاي بي المصرح لها باستخدام API بحيث يكون كل اي بي في قيد خاص به.

3. التعديل على الكود البرمجي لدالة middleware handle لتقوم بجلب عناوين الاي بي من قاعدة البيانات وفحصها بدلا من استخدام المصفوفة

الان نقوم بالتعديل على الكود البرمجي لملف app/Http/Middleware/IPAccessControl.php ليصبج كالتالي:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
use App\Models\AllowedIp;

class IPAccessControl
{

    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        $ip = $request->ip();
        
        // جلب عناوين الاي بي من قاعدة البيانات كمصفوفة
        $allowedIPs = AllowedIp::pluck('ip_address')->toArray();

        // التحقق من ان العنوان الاي بي موجود ضمن القائمة المسموح بها
        if (!in_array($request->ip(), $allowedIPs)) {
            return response()->json([
                'message' => 'Unauthorized access: Your IP address is not permitted to use this API.',
                'status' => 403,
            ], 403);
        }

        return $next($request);
    }
}

وبهذا نكون قد غيرنا طريقة فحص عناوين الاي بي لتكون في جدول قاعدة بيانات بدلا من وجودها في مصفوفه كما كانت في المثال السابق،

الان يمكنك برمجة الاليه التي تسمح فيها للمشرفين على اضافه عناوين الاي بي المسموح لها بالوصول الي API من خلال ال backend الخاصه بك بالطريقه المناسبه حيث انني سوف اكتفي الي هنا بهذا القدر.