آموزش نحوه اضافه کردن احراز هویت دو مرحله ای گوگل به لاراول

two-factor-authentication-plugin

لاراول یکی از فریمورک های محبوب php است که به ما امکان ساخت برنامه های تحت وب با زبان php را می دهد.

یکی از امکانات وب این فریمورک امکان راه اندازی راحت قابلیت احراز هویت برای برنامه های تحت وب است. این قابلیت به ما امکان ثبت نام از کاربران و حتی بازیابی کلمه عبور آنها را می دهد.

اگر چه در حال حاضر لاگین کردن به سایت توسط ایمیل و کلمه عبور یکی از روش های مرسوم است، اما باید بدانید که امنیت این روش روز به روز پایین می آید.

معمولاً هکرها با حملات Brute force، فیشینگ، دستکاری داده ها، و تزریق SQL سعی دارند امنیت سیستم احراز هویتی که فقط از ایمیل و پسورد برای ورود به حساب کاربری استفاده می کنند، را بشکنند، و حساب کاربری آنها را هک کنند.

همچنین استفاده از کلمه های عبور ضعیف و یکسان برای حساب های کاربری مختلف، و شبکه های WiFi ناامن، همگی افراد را در معرض حمله هکرها قرار می دهد.

احراز هویت دو مرحله ای لاراول (2FA) قابلیتی است که برای تایید هویت یک فرد از دو روش (یا دو فاکتور) استفاده می شود.

این قابلیت کاربران را در برابر حملات فیشینگ، مهندسی اجتماعی و حملات Brute Force محافظت می کند. همچنین باعث جلوگیری از اکسپلویت شدن فرم لاگین و دزدیدن مشخصات ورود به حساب کاربری می شود.

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

مشخصات این الگوریتم در RFC6238 آمده است.

برای استفاده از احراز هویت دو مرحله ای لاراول، کاربران وب سایت تان باید برنامه Google Authenticator را در سیستم شان نصب کنند.

این برنامه برای سیستم عامل های مختلفی عرضه شده که در زیر می بینید:

سرفصل های این آموزش

  1. شروع کار
  2. راه اندازی سیستم احراز هویت لاراول
  3. افزودن قابلیت احراز هویت دو مرحله ای لاراول در حین ثبت نام
  4. افزودن قابلیت احراز هویت دو مرحله ای لاراول در حین ورود به سیستم

شروع کار

نصب لاراول

برای شروع ابتدا لاراول را در فولدر laravel-2fa نصب می کنیم

composer create-project --prefer-dist laravel/laravel laravel-2fa

# set proper folder permissions
sudo chmod -R 777 laravel-2fa/storage laravel-2fa/bootstrap/cache

ترمینال را باز کرده و با دستور زیر برنامه را راه اندازی کنید.

php artisan serve --port=8000

با اجرای دستور بالا، برنامه مطابق با تصویر زیر در مرورگر اجرا می شود.

اجرای لاراول

اتصال به پایگاه داده

در این آموزش از پایگاه داده MySQL استفاده می کنیم، اما برای کار با سایر بانک های اطلاعاتی، روند مشابهی طی می شود.

پیکربندی های زیر را به فایل .env اضافه کنید.

# .env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret

همچنین خطوط زیر را هم باید بروزرسانی کنید.

# .env
APP_NAME=Laravel 2FA Demo
APP_URL=http://localhost:8000

کدهای فوق باعث می شود تا نام برنامه متفاوت از نام پیش فرضی که لاراول برای آن انتخاب کرده باشد. همچنین آدرس برنامه را هم مطابق با کدهای فوق بروزرسانی می کنیم.

راه اندازی قابلیت احراز هویت در لاراول

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

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

php artisan make:auth

# create the database tables needed with
php artisan migrate

حال اگر برنامه را در مرورگر مشاهده کنید، می بینید که در قسمت بالای برنامه دو لینک به نام های Register و Login اضافه شده است.

 احراز هویت در لاراول

برای ثبت نام یک کاربر باید به آدرس http://localhost:8000/register مراجعه کنید.

اضافه کردن احراز هویت دو مرحله ای در حین ثبت نام

هدف از این بخش عبارت است از:

1- هنگامی که کاربر جدیدی در سایت ثبت نام کند، یک secret code برای Autheticator تولید می کنیم.

2- در درخواست های بعدی، از همان secret code برای نمایش QR Code به کاربر در برنامه Google Authenticator استفاده می کنیم.

3- هنگامی که کاربر روی دکمه OK کلیک کرد، کاربر را با استفاده از همان secret code ثبت نام می کنیم.

در این روش صفحه QR Code تنها یکبار قابل دسترس است، که اینکار باعث افزایش امنیت می شود. اگر کاربر دوباره بخواهد احراز هویت دو مرحله ای لاراول را راه اندازی کند باید چرخه فوق را دوباره تکرار کند، چون چرخه قبلی دیگر معتبر نیست.

برای انجام اینکار ما یک مرحله دیگر برای Google Authenticator قبل از اینکه یک کاربر را در پایگاه داده ثبت کند، قرار می دهیم.

برای تغییر چرخه ثبت نام، باید متد register را در کنترلر RegisterController تعریف کنیم.(این کنترلر در مسیر app/Http/Controllers/Auth/RegisterController قرار دارد.

تولید و نمایش secret code

ابتدا باید دو پکیج زیر را نصب کنیم.

composer require pragmarx/google2fa-laravel
composer require bacon/bacon-qr-code

سپس با دستور زیر فایل پیکربندی را publish کنیم.

php artisan vendor:publish --provider=PragmaRX\\Google2FALaravel\\ServiceProvider

سپس کلاس request را مطابق زیر به کنترلر RegisterController اضافه می کنیم.

// app/Http/Controllers/Auth/RegisterController.php

use Illuminate\Http\Request;

سپس باید متد register را در فایل RegisterController اضافه کنیم.

 // app/Http/Controllers/Auth/RegisterController.php

    public function register(Request $request)
    {
        //Validate the incoming request using the already included validator method
        $this->validator($request->all())->validate();

        // Initialise the 2FA class
        $google2fa = app('pragmarx.google2fa');

        // Save the registration data in an array
        $registration_data = $request->all();

        // Add the secret key to the registration data
        $registration_data["google2fa_secret"] = $google2fa->generateSecretKey();

        // Save the registration data to the user session for just the next request
        $request->session()->flash('registration_data', $registration_data);

        // Generate the QR image. This is the image the user will scan with their app
     // to set up two factor authentication
        $QR_Image = $google2fa->getQRCodeInline(
            config('app.name'),
            $registration_data['email'],
            $registration_data['google2fa_secret']
        );

        // Pass the QR barcode image to our view
        return view('google2fa.register', ['QR_Image' => $QR_Image, 'secret' => $registration_data['google2fa_secret']]);
    }

همچنین برای نمایش QR Code باید یک ویو ایجاد کنیم. برای اینکار یک فولدر به نام google2fa داخل فولدر resources/views ایجاد کنید و درون فولدر google2fa یک فایل با نام register.blade.php قرار دهید.

سپس کدهای زیر را درون فایل register.blade.php قرار دهید.

// resources/views/google2fa/register.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">Set up Google Authenticator</div>

                <div class="panel-body" style="text-align: center;">
                    <p>Set up your two factor authentication by scanning the barcode below. Alternatively, you can use the code {{ $secret }}</p>
                    <div>
                        <img src="{{ $QR_Image }}">
                    </div>
                    <p>You must set up your Google Authenticator app before continuing. You will be unable to login otherwise</p>
                    <div>
                        <a href="/complete-registration"><button class="btn-primary">Complete Registration</button></a>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

حال بلافاصله بعد از ثبت نام، کاربر با صفحه زیر مواجه می شود که یک QR Code و Secret code به کاربر نمایش داده می شود که باید توسط Google Authenticator آنرا اسکن و به برنامه لاگین کند.

 احراز هویت دو مرحله ای با google2fa

ثبت نام کاربران

متاسفانه هنگامی که یک کاربر بخواهد در سایت ثبت نام کند، با یک خطا مواجه می شود. برای رفع این خطا باید روت ها و کنترلرهای مناسب را برای ثبت نام کاربران، پیکربندی کنیم.

قبل از اینکار باید یک فیلد برای secret code در جدول users ایجاد کنیم. برای شروع، ابتدا یک migration ایجاد کنید.

php artisan make:migration add_google2fa_column_to_users --table=users

سپس کدهای زیر را در فایل migration ساخته شده قرار دهید.

// database/migrations/201X_XX_XX_XXXXXX_add_google2fa_column_to_users.php

<?php

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

class AddGoogle2faColumnToUsers extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
         // add a text column in the users table for the google2fa_secret
            $table->text('google2fa_secret');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
         // drop the column if the migration is rolledback
            $table->dropColumn('google2fa_secret');
        });
    }
}

درصورت اجرای اینmigration یک ستون با نام google2fa_secret در جدول users ایجاد می شود و هنگامی که عمل rollback را انجام می دهیم، آن ستون حذف خواهد شد.

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

php artisan migrate

در قدم بعدی، باید از متد register استفاده کنیم.برای اینکار کنترلر RegisterController را باز کرده و کد زیر را پیدا کنید:

 // app/Http/Controllers/Auth/RegisterController.php

    use RegistersUsers;

و آن کدها را مطابق زیر تغییر دهید:

  // app/Http/Controllers/Auth/RegisterController.php

    use RegistersUsers {
     // change the name of the name of the trait's method in this class
     // so it does not clash with our own register method
        register as registration;
    }

در قدم بعدی یک روت به نام complete-registration ایجاد می کنیم. فایل routes/web.php را باز کنید و کدهای زیر را در آن قرار دهید.

// routes/web.php 

Route::get('/complete-registration', 'Auth\RegisterController@completeRegistration');

حال باید متد completeRegistration را در کنترلر RegisterController تعریف کنیم.

 // app/Http/Controllers/Auth/RegisterController.php

    public function completeRegistration(Request $request)
    {        
        // add the session data back to the request input
        $request->merge(session('registration_data'));

        // Call the default laravel authentication
        return $this->registration($request);
    }

متاسفانه سیستم احراز هویت پیش فرض لاراول فقط نام، ایمیل، و کلمه عبور را ذخیره می کند. برای استفاده از google2fa باید متد create را مطابق زیر ویرایش کنیم.

  // app/Http/Controllers/Auth/RegisterController.php

    protected function create(array $data)
    {
        return User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => bcrypt($data['password']),
            'google2fa_secret' => $data['google2fa_secret'],
        ]);
    }

در قدم بعدی مدل User را باز کرده و google2fa_secret را به پروپرتی $fillable آن اضافه کنید.

همچنین به دلیل اینکه می خواهیم هنگام تبدیل جدول به آرایه یا json مقدار این پررپرتی را مخفی نگه داریم، آن را در پروپرتی $hidden هم قرار می دهیم.

  // app/User.php

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password', 'google2fa_secret',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token', 'google2fa_secret',
    ];

سپس برای امنیت بیشتر باید مقدار google2fa_secret را رمزنگاری کنیم. برای اینکار مدل User را باز کرده و کدهای زیر را به آن اضافه کنید.

  // app/User.php

    /**
     * Ecrypt the user's google_2fa secret.
     *
     * @param  string  $value
     * @return string
     */
    public function setGoogle2faSecretAttribute($value)
    {
         $this->attributes['google2fa_secret'] = encrypt($value);
    }

    /**
     * Decrypt the user's google_2fa secret.
     *
     * @param  string  $value
     * @return string
     */
    public function getGoogle2faSecretAttribute($value)
    {
        return decrypt($value);
    }

حال کاربر به راحتی می تواند در سایت ثبت نام کرده و یا لاگین کند.

 ثبت نام کاربر در لاراول

اضافه کردن احراز هویت دو مرحله ای لاراول در حین ثبت نام

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

هدف ما در این بخش این است که کاربران قبل از دسترسی کامل با سایت باید کد Google Authenticator شان را وارد کنند.

بهترین کار این است که این قابلیت را توسط یک middleware پیاده سازی کنیم.

خوشبختانه پکیج pragmaix/google2fa-laravel یک middleware برای اینکار ارائه داده است.

برای استفاده از این middleware باید آن را در آرایه routeMiddleware که در فایل app/Http/kernel.php قرار دارد، بگذاریم.

 // app/Http/Kernel.php

    protected $routeMiddleware = [
        ...
        '2fa' => \PragmaRX\Google2FALaravel\Middleware::class,
    ];

با انجام اینکار می توانیم از 2fa برای ارجاع به middleware در هر زمان که نیاز داشتیم استفاده کنیم.

سپس یک ویو برای قسمتی که کاربر بعد از لاگین به سایت باید OTP (رمز یکبار مصرف) را وارد کند، ایجاد می کنیم.

بطور پیش فرض برای ویوی resources/views/google2fa/index.blade.php پیکربندی شده است.

حال این ویو را ایجاد و کدهای زیر را در آن قرار می دهیم.

// resources/views/google2fa/index.blade.php 

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">Register</div>

                <div class="panel-body">
                    <form class="form-horizontal" method="POST" action="{{ route('2fa') }}">
                        {{ csrf_field() }}

                        <div class="form-group">
                            <label for="one_time_password" class="col-md-4 control-label">One Time Password</label>

                            <div class="col-md-6">
                                <input id="one_time_password" type="number" class="form-control" name="one_time_password" required autofocus>
                            </div>
                        </div>

                        <div class="form-group">
                            <div class="col-md-6 col-md-offset-4">
                                <button type="submit" class="btn btn-primary">
                                    Login
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

حال باید یک روت تعریف کنیم تا بعد از اینکه middleware صحت OTP را بررسی کرد، کاربر را به آدرس اصلی هدایت کند.

کدهای زیر را به فایل routes/web.php اضافه کنید.

// routes/web.php

Route::post('/2fa', function () {
    return redirect(URL()->previous());
})->name('2fa')->middleware('2fa');

در بالا یک روت برای پاسخ به درخواست ارسال شده از http://localhost:8000/2fa تعریف کرده و کاربر را به آدرس اصلی هدایت می کنیم.

حال می توانیم از این middleware برای محدود کردن قسمت های مختلف برنامه استفاده کنیم.

برای مثال کدهای زیر را در کنترلرHomeController پیدا کرده:

 // app/Http/Controllers/HomeController.php

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
    }

و آنرا مطابق زیر تغییر دهید:

    // app/Http/Controllers/HomeController.php

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware(['auth', '2fa']);
    }

به این ترتیب بعد از لاگین به سایت، کاربر به مسیر /home هدایت شده و در آنجا باید پسورد یکبار مصرف (OTP) را وارد کند.

 وارد کردن پسورد یکبار مصرف در احراز هویت دومرحله در لاراول

هنگامی که پسورد را وارد کرد، می تواند بطور کامل به سایت وارد شود، به این ترتیب توانستیم با موفقیت سیستم احراز هویت دو مرحله ای لاراولGoogle Authenticator را به وب سایت لاراولی مان اضافه کنیم.

نویسنده شوید

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

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

افشین
09 آذر 1398
ممنون خیلی خوب بود و عالی فقط یه بار خطا داد که اونم سرچ زدم اکثر کابر ها پیشنهاد داده بودن از این ورژن Bacon استفاده بشه composer require bacon/bacon-qr-code:~1.0.3

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

مصطفی
08 اسفند 1397
با سلام موقع نصب هر دو پکیج بالا با پیغام زیر مواجه میشم . علت چیه ؟ با تشکر ‍‍‍``` [Composer\Downloader\TransportException] The "http://repo.packagist.org/p/pragmarx/google2fa-laravel%242c395aa48d852 e6b74de301ef54691764f318e5d48c5d69065a5bdd9fb0bbb4f.json" file could not be downloaded: failed to open stream: HTTP request failed! ```

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