محافظت از سایت های لاراولی با کنترل IP کاربران

ipapi-laravel

از لحظه ای که سایت خود را منتشر کردید باید مراقب مسائل امنیتی مربوط به آن باشید، چون امکان دارد از سمت هکرها تحت حملات سایبری قرار بگیرد.

بنابراین به عنوان یک توسعه دهنده باید همیشه به دنبال این باشیم که چطور از وب سایت محافظت کنیم. در این مقاله، روش های را بررسی خواهیم کرد که توسط آنها می توانید با استفاده از کنترل IP، اتصالات (کانکشن ها) ناخواسته به وب سایت خود را شناسایی کنید، و از ورود درخواست های نا امن به وب سایت جلوگیری کنید.

سرفصل های این فصل

  1. کنترل IP چیست؟
  2. شروع کار
  3. ارسال یک درخواست به سرور IPAPI
  4. ساخت Middleware
  5. بهبود دادن کارایی
  6. نتیجه گیری

کنترل IP چیست؟

هنگامی که اکثر افراد عبارت کنترل IP را می شنوند، فکر می کنند منظور ما « شناسایی مکان کاربر از روی آدرس IP آن» است. اما کنترل IP فقط محدود به این نمی شود. با کنترل IP می توان کارهای زیادی انجام داد. مثلاً کارهایی از قبیل:

  • شخصی سازی محتوا
  • تشخیص واحد ارزی (پول)
  • تشخیص تقلب
  • پیدا کردن زمان منطقه ای (Time Zone)
  • تشخیص زبان کاربران و هدایت آنها به مسیر درست

لیست بالا تنها نمونه کوچکی از کارهایی است که توسط کنترل IP می توان انجام داد.

ساخت سرویسی که بتواند تمام کارهای بالا را انجام دهد، می تواند زمان و منابع زیادی را از شما بگیرد. از اینرو به جای اینکه همچین سرویسی را طراحی و مدیریت کنیم، از سرویس IPAPI استفاده می کنیم.

کنترل IP کاربران در لاراول - شروع کار

یک فایروال تحت عنوان Middleware در برنامه ایجاد خواهیم کرد و درخواست هایی  که به سمت برنامه وارد شود، از این فیلتر عبور می کند. و درخواست هایی که مشکوک هستند اجازه دسترسی به برنامه را نخواهند داشت.

حال برای ساخت یک Middlewareیی که از برنامه محافظت کند، یک پروژه لاراولی را ایجاد می کنیم. دقت داشته باشید که این کار توسط هر زبان برنامه نویسی دیگری که بخواهید، قابل انجام است.

composer create-project laravel/laravel firewall --prefer-dist

سپس به سایت IPAPI رفته و یک اکانت ایجاد کنید. بعد از آن، یک کلید محرمانه شبیه به ساختار 86ebc30b4adfc508e48bf1b489140fe3 را مشاهده خواهید کرد. کلید مربوط به خود را کپی کرده و آن را در فایل .env پروژه خود paste کنید.

IPAPI_ACCESS_KEY=86ebc30b4adfc508e48bf1b489140fe3

سپس فایل config/services.php را باز کرده و مقدار آرایه زیر را به آن اضافه کنید.

'ip' => [
    'key' => env('IPAPI_ACCESS_KEY'),
],

در قدم آخر باید GuzzleHttp را که برای ایجاد یک درخواست به سرور IPAPI استفاده می شود، را نصب کنیم.

composer require guzzlehttp/guzzle

بعد از انجام این کارها می توانیم middleware را ایجاد کنیم.

ایجاد یک درخواست به سرور IPAPI

سرور IPAPI دو آدرس (یا endpoint) برای استفاده از سرویس اش ارائه می دهد.

  • ipapi.com/<ip>: آدرس IPیی که می خواهیم بررسی کنیم را به این آدرس ارسال می کنیم.
  • ipapi.com/check: آدرس های IP ورودی را حدس زده و یک پاسخ به آن ارسال می کند (برای درخواست هایی که از سمت مرورگر به آن ارسال می شود، مناسب است).

در این مقاله بیشتر از آدرس اولی استفاده خواهیم کرد، چون آدرس دومی برای بازیابی IP سرور ما به جای درخواست ورودی استفاده می شود.

پس برای استفاده از آدرس اولی باید IP کاربران را گرفته و آن را به IPAPI ارسال کنیم.

برای مثال، درخواست زیر را به آدرس اولی ارسال می کنیم.

GET https://api.ipapi.com/api/161.185.160.93?access_key=86ebc30b4adfc508e48bf1b489140fe3

در پاسخ، کد زیر را دریافت می کنیم.

{
    "ip": "161.185.160.93",
    "hostname": "161.185.160.93",
    "type": "ipv4",
    "continent_code": "NA",
    "continent_name": "North America",
    "country_code": "US",
    "country_name": "United States",
    "region_code": "NY",
    "region_name": "New York",
    "city": "Brooklyn",
    "zip": "11238",
    "latitude": 40.676,
    "longitude": -73.9629,
    "location": {
        "geoname_id": 5110302,
        "capital": "Washington D.C.",
        "languages": [
            {
                "code": "en",
                "name": "English",
                "native": "English"
            }
        ],
        "country_flag": "http://assets.ipapi.com/flags/us.svg",
        "country_flag_emoji": "🇺🇸",
        "country_flag_emoji_unicode": "U+1F1FA U+1F1F8",
        "calling_code": "1",
        "is_eu": false
    },
    "time_zone": {
        "id": "America/New_York",
        "current_time": "2018-09-24T05:07:10-04:00",
        "gmt_offset": -14400,
        "code": "EDT",
        "is_daylight_saving": true
    },
    "currency": {
        "code": "USD",
        "name": "US Dollar",
        "plural": "US dollars",
        "symbol": "$",
        "symbol_native": "$"
    },
    "connection": {
        "asn": 22252,
        "isp": "The City of New York"
    },
    "security": {
        "is_proxy": false,
        "proxy_type": null,
        "is_crawler": false,
        "crawler_name": null,
        "crawler_type": null,
        "is_tor": false,
        "threat_level": "low",
        "threat_types": null
    }
}

همان طور که می بینید IPAPI کارهای زیادی را برای ما انجام می دهد. اما در این مقاله بیشتر به بخش Security آن می پردازیم.

...
    "security": {
        "is_proxy": false,
        "proxy_type": null,
        "is_crawler": false,
        "crawler_name": null,
        "crawler_type": null,
        "is_tor": false,
        "threat_level": "low",
        "threat_types": null
    } ...

همانطور که می بینید این خروجی از درجه بندی امنیتی گرفته تا بررسی اینکه آیا درخواست ورودی از سوی شبکه TOR است یا خیر، برای ما ارسال می کند.

حتی مشخص می کند که آیا درخواست ورودی از سمت یک خزنده (Crwaler) بوده یا خیر.

ایجاد Middleware

Middleware سازوکاری است که بین یک درخواست ورودی و برنامه ما قرار می گیرد.

حال، دستور زیر را در ترمینال اجرا کنید.

php artisan make:middleware IPFirewall

بعد از اینکه Middleware خود را ایجاد کردید، می توانید آن را از مسیر app/Http/Middleware/IPFirewall.php باز کنید.

<?php

namespace App\Http\Middleware;

use Closure;

class IPFirewall
{
  /**
   * Handle an incoming request.
   *
   * @param  \Illuminate\Http\Request  $request
   * @param  \Closure  $next
   * @return mixed
   */
  public function handle($request, Closure $next)
  {
    return $next($request);
  }
}

حال برای محافظت از سرور سایت، کارهای زیر را انجام می دهیم.

public function handle($request, Closure $next)
{
    $ip = $request->ip();

    $key = config('services.ip.key');
    $url = "http://api.ipapi.com/api/{$ip}?access_key={$key}&security=1";

    // make request
    $client = new Client;
    $response = $client->request('GET', $url);
    $data = json_decode((string) $response->getBody(), true);

    if (!array_key_exists('security', $data)) {
        return false;
    }

    return $data['security']['threat_level'] === 'high' ? abort(403) : $next($request);
}

تشریح کد بالا:

  • ابتدا آدرس IP ورودی کاربر را دریافت میکنیم.
  • سپس یک درخواست برای ارسال به IPAPI ایجاد می کنیم.
  • هنگامی که پاسخ از سمت IPAPI دریافت شد، بررسی می کنیم که آیا بخش Security وجود دارد یا خیر.
  • سپس باید ببینیم که اگر سطح تهدید آن درخواست بالا است، دسترسی کاربر را محدود می کنیم.

بهبود دادن کارایی

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

برای راه حل این موضوع از لایه کش لاراول استفاده می کنیم.

public function handle($request, Closure $next)
{
    $ip = $request->ip();
    $insecureRequest = Cache::remember("firewall_$ip", function() use ($ip) {
        // build parameters
        $key = config('services.ip.key');
        $url = "http://api.ipapi.com/api/{$ip}?access_key={$key}&security=1";
        // make request
        $client = new Client;
        $response = $client->request('GET', $url);
        $data = json_decode((string) $response->getBody(), true);
        if (!array_key_exists('security', $data)) {
            return false;
        }
        return $data['security']['threat_level'] === 'high' ?? false;
    });
    return $insecureRequest ? abort(403) : $next($request);
}

با فراخوانی cache::remember() به لاراول می گوییم که مقدار را از کش بازیابی کند، اگر آن وجود نداشت، یک closure را اجرا کرده و مقدار را از closure برگردانده و به کش می دهد.

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

نتیجه گیری

IPAPI سرویسی بسیار کاربردی است که توسط شرکت های زیادی استفاده می شود و باعث بهبود امنیت برنامه های تحت وب می شود.

نویسنده شوید

دیدگاه‌های شما (3 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

سجاد
15 آذر 1398
با سلام. آموزش جالبی بود، فقط درمورد کش، یک کمی بیشتر توضیح میدادید رتبه آموزشی که تهیه کردید بسیار بهتر میشد؛ با این وجود بابت مطلب کاربردی که زحمت آن را کشیده اید بی نهایت متشکرم :)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

مسعود
27 آبان 1398
اقا سلام اگه میشه در مورد الستیک سرچ در لاراول اموزش بدید با پکیج rufix/elastcsearch اموزش بدید و یک توضیح در موردindexو mappingو...توضیح بدید ممنون

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

سینا
20 دی 1397
سلام خسته نباشید چطوری میشه کاربرانی که با پروکسی وارد سایت میشن رو بلاک کرد آیا این کار امکان پذیر هست و سوال دوم اینکه چطوری میشه کاربرانی که مثلا پنج بار اشتباه اطلاعات کاربری خود رو وارد کرد برای ۴۸ ساعت بندازیم توی لیست سیاه .آیا پکیجی برای این کارا وجود داره یا باید خودمون بنویسیم ؟

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.