實作 二階段驗證/雙重驗證 2FA — 以 Laravel 為例

by Benmr

前言

或許大家已經對 二階段驗證 (Two-factor authentication) 不陌生

主要就是為了防止有心人士在獲得你的帳號密碼後,就得以登入並進行犯罪

二階段驗利用手機、或任何只有你才知道的資訊來進行第二層驗證

因此提高了安全性

主要的流程如下

實例操作流程

  1. 使用者在登入後進入設定頁來設置二階段驗證 (可用工具如 Google Authenticator 、 Authy 等)
  2. 系統將藉工具產生的二階段驗碼當作 key 存入 server
  3. 當使用者要再次登入或進行具機敏性的操作時,須額外輸入二階段驗證工具產生的 code
  4. 系統驗證二階段驗證工具產生 code,在經過編碼後,是否與 server 內的 key 一致

以 Laravel 實作

以下將以 Laravel 實作

並只處理後端的部份,略過前端畫面 render

前置作業

composer require pragmarx/google2fa

Route

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TestController;

Route::post('twoFa-create', [TestController::class, 'twoFaCreate']);
Route::post('twoFa-verify', [TestController::class, 'twoFaVerify']);

Controller

  1. 使用 Google2FA 物件來產生 key 存入 db,並回傳 url 至前端供 user 以二階段驗證工具綁定
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
use PragmaRX\Google2FA\Google2FA;

class TestController extendsBaseController
    public function twoFaCreate(Request $request)
    {
        $id = $request->id;

        $google2fa = new Google2FA();

        $secret = $google2fa->generateSecretKey();

        // 找到目前登入的 user 並將套件產生的二階段驗證碼存入
        $updateDate = [
            'google2fa_token' => $secret
        ];
        User::query()
            ->where('id', $id)
            ->update($updateDate);

              // 使用工具產生 unique 的 url,讓使用者可以用二階段驗證工具掃碼存入
        $qrCodeUrl = $google2fa->getQRCodeUrl(
            'testUser',
            'testUser@gmail.com',
            $secret
        );

        // qrCodeUrl 可以直接用 google 的工具轉成 qrcode ,或給前端自己產。 見註1

              return $qrCodeUrl;

        // 根據 userId 取出
        $secret = '4YI2RPLREM64FKDM';

        $otp = '633672';

        $valid = $google2fa->verifyKey($secret, $otp);
        dd($valid);

        return $google2fa->generateSecretKey();
    }

}
  • 註1: 這邊可以使用 google 的工具將 url 轉變成圖片
    範例如下,掃了之後就可以得到 otpauth://totp/test:test%40gmail.com?secret=4YI2RPLREM64FKDM ,給二階段驗證工具使用


cht=qr
chl=otpauth://totp/test:test%40gmail.com?secret=4YI2RPLREM64FKDM
choe=UTF-8

  1. 驗證使用者輸入的 code 是否合法
    public function twoFaVerify(Request $request)
        {
            $user = User::findById($request->id);
            $otpCode = $request->otpCode;

      $google2fa = new Google2FA();
            // 使用 verifyKey 來驗證是否是合法 code
            $valid = $google2fa->verifyKey($secret, $otp);

            // 繼續處理你要的東西...
    }
  1. 完成!

參考資料

You may also like

Leave a Comment