+3

Series Laravel & Google 2FA Thực chiến #1: Giải mã TOTP và Khởi tạo khiên thép

1. Google Authenticator hoạt động như thế nào? (Thuật toán TOTP)

Nhiều anh em lầm tưởng rằng khi mở app Google Authenticator lên, app sẽ gọi API về server của Google, rồi server Google lại gọi về hệ thống của chúng ta để lấy mã 6 số. Thực tế hoàn toàn không phải vậy! Thuật toán này có thể chạy offline 100% không cần mạng.

Thuật toán đằng sau nó gọi là TOTP (Time-based One-Time Password). Cơ chế của nó cực kỳ thanh lịch và dựa trên 2 biến số:

  1. Secret Key (Khóa bí mật): Một chuỗi mã ngẫu nhiên cực dài (thường là Base32) được sinh ra cho từng user khi họ thiết lập 2FA. Cả Server của bạn và App Google Authenticator trên điện thoại user đều lưu chung chuỗi này.
  2. Current Time (Thời gian hiện tại): Thời gian chuẩn của thế giới (UTC), được làm tròn theo các block 30 giây.

Công thức: Hash(Secret Key + Current Time) = Mã 6 số.

Vì cả Server và Điện thoại đều biết Secret Key và đều có chung Current Time, nên cả hai sẽ tự động tính toán ra được cùng một mã 6 số ở cùng một thời điểm. Cứ mỗi 30 giây, thời gian thay đổi, mã 6 số lại nhảy sang một giá trị mới.

2. Cài đặt vũ khí vào Laravel

Để làm việc với thuật toán TOTP một cách chuẩn xác nhất mà không cần tự code tay hàm băm, hệ sinh thái Laravel có một package "quốc dân" cực kỳ mạnh mẽ.

Bạn hãy mở Terminal, chui vào container PHP (hoặc chạy trực tiếp nếu dùng local) và gõ lệnh:

composer require pragmarx/google2fa-laravel

Tiếp theo, hãy publish file cấu hình của package này ra ngoài để sau này dễ dàng tinh chỉnh (ví dụ đổi thời gian sống của OTP hoặc đổi tên hệ thống hiển thị trên app):

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

Lúc này, một file config/google2fa.php sẽ xuất hiện trong thư mục của bạn.

3. Nâng cấp Database: Nơi cất giấu Secret Key

Để hệ thống biết được mã OTP của user A khác với user B, chúng ta cần lưu trữ cái Secret Key của mỗi người.

Hãy tạo một file migration để thêm cột google2fa_secret vào bảng users hiện tại:

php artisan make:migration add_google2fa_secret_to_users_table

Mở file migration vừa được tạo ra trong thư mục database/migrations/ và viết logic:

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

return new class extends Migration
{
    public function up(): void
    {
        Schema::table('users', function (Blueprint $table) {
            // Thêm cột text để lưu mã bí mật. Cho phép null vì không phải ai cũng bật 2FA ngay
            $table->text('google2fa_secret')->nullable()->after('password');
        });
    }

    public function down(): void
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('google2fa_secret');
        });
    }
};

Sau khi lưu file, bạn gõ lệnh để cập nhật Database thực tế:

php artisan migrate

4. Khai báo thuộc tính trong Model

Đừng quên cập nhật Model User để Laravel cho phép chúng ta lưu chuỗi bí mật này qua các hàm Eloquent.

Mở file app/Models/User.php và thêm cột mới vào mảng $fillable:

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    protected $fillable = [
        'name',
        'email',
        'password',
        'google2fa_secret', // <-- Cấp phép lưu trữ trường này
    ];

    // Che giấu trường này khi API trả về object User (Rất quan trọng về bảo mật!)
    protected $hidden = [
        'password',
        'remember_token',
        'google2fa_secret', 
    ];
}

Tổng kết Bài 1

Chúng ta đã bóc tách được bản chất offline tĩnh lặng nhưng cực kỳ chuẩn xác của thuật toán TOTP, đồng thời thiết lập xong các thư viện cốt lõi và cột dữ liệu cần thiết trong MySQL. Hạ tầng Backend đã sẵn sàng.

Ở Bài 2, chúng ta sẽ bắt tay vào code luồng Thiết lập 2FA (Setup Flow): Tạo ra chuỗi Secret ngẫu nhiên, mã hóa nó thành một mã QR Code cực ngầu để nhân viên trạm có thể quét bằng app Google Authenticator trên điện thoại, và viết API xác nhận mã lần đầu tiên để kích hoạt khiên thép!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí