📌

Passkey là gì?

Công nghệ xác thực không mật khẩu

Passkey là công nghệ xác thực dựa trên chuẩn WebAuthn (Web Authentication API) và FIDO2. Passkey cho phép người dùng đăng nhập bằng sinh trắc học (vân tay, Face ID) hoặc mã PIN thiết bị thay vì mật khẩu truyền thống.

💡 Ưu điểm chính:
• An toàn hơn mật khẩu - không thể bị phishing, keylogger
• Tiện lợi - đăng nhập nhanh với vân tay/Face ID
• Chống Replay Attack - mỗi lần dùng challenge khác nhau
• Đồng bộ đa thiết bị qua iCloud/Google Password Manager

Các thành phần chính

Thành phần Mô tả
Authenticator Thiết bị tạo và lưu credential (điện thoại, máy tính, security key)
Relying Party (RP) Website/ứng dụng yêu cầu xác thực (server Laravel)
Client Trình duyệt web thực hiện giao tiếp giữa Authenticator và RP
Public/Private Key Cặp khóa mật mã được tạo cho mỗi credential
🔄

Cơ chế hoạt động

Quy trình đăng ký (Registration)

1. User yêu cầu
đăng ký Passkey
2. Server tạo
Challenge
3. Browser gọi
WebAuthn API
4. Authenticator
tạo Key Pair
5. Server lưu
Public Key

Client gửi yêu cầu đăng ký

User nhấn "Thêm Passkey". Frontend gọi /webauthn/register/options.

Server tạo Challenge và Options

Server tạo challenge ngẫu nhiên (16 bytes), trả về RP info, user info.

Authenticator tạo Key Pair

Private Key lưu an toàn trong Secure Enclave/TPM.

Quy trình đăng nhập (Authentication)

1. User yêu cầu
đăng nhập
2. Server gửi
Challenge mới
3. Authenticator
ký Challenge
4. Server xác minh
chữ ký
5. User được
đăng nhập
🔒 Quan trọng: Private Key không bao giờ rời khỏi thiết bị. Server chỉ lưu Public Key, nên ngay cả khi database bị tấn công, attacker không thể mạo danh người dùng.
⚙️

Hướng dẫn cài đặt

Cài đặt Package

# Cài đặt Laragear WebAuthn
composer require laragear/webauthn

# Publish cấu hình và migration
php artisan vendor:publish --provider="Laragear\WebAuthn\WebAuthnServiceProvider"

# Chạy migration
php artisan migrate

Cấu hình User Model

<?php

namespace App\Models;

use Laragear\WebAuthn\Contracts\WebAuthnAuthenticatable;
use Laragear\WebAuthn\WebAuthnAuthentication;

class User extends Authenticatable implements WebAuthnAuthenticatable
{
    use WebAuthnAuthentication;
    
    // ... existing code
}

Đăng ký Routes

// routes/web.php
use Laragear\WebAuthn\Http\Routes as WebAuthnRoutes;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;

// Đăng ký WebAuthn routes
WebAuthnRoutes::register()->withoutMiddleware(VerifyCsrfToken::class);

Cấu trúc dự án

  • 📁 app/
    • 📁 Http/Controllers/
      • 📄 AuthController.php - Xử lý login/register
    • 📁 Models/
      • 📄 User.php - Model user với WebAuthn trait
  • 📁 config/
    • 📄 webauthn.php - Cấu hình WebAuthn
  • 📁 database/migrations/
    • 📄 create_webauthn_credentials.php
💻

Code Frontend

Thêm Passkey mới

// Đăng ký Passkey sau khi đã login
document.getElementById('passkey-register').addEventListener('click', async function() {
    try {
        const { credential, success, error } = await Webpass.attest(
            '/webauthn/register/options',  // Endpoint lấy options
            '/webauthn/register'           // Endpoint gửi credential
        );

        if (success) {
            alert('Passkey đã được thêm thành công!');
        } else {
            alert(error || 'Không thể thêm Passkey.');
        }
    } catch (err) {
        alert(err.message);
    }
});
⚠️ Lưu ý:
• User phải đã đăng nhập để đăng ký Passkey
• Một user có thể có nhiều Passkey (nhiều thiết bị)
• Passkey được liên kết với domain cụ thể (RP ID)

Đăng nhập bằng Passkey

document.getElementById('passkey-login').addEventListener('click', async function() {
    try {
        const email = document.getElementById('login-email').value;
        
        const optionsUrl = '/webauthn/login/options' + 
            (email ? `?email=${encodeURIComponent(email)}` : '');
        
        const { user, success, error } = await Webpass.assert(
            optionsUrl,
            '/webauthn/login'
        );

        if (success) {
            window.location.href = '/dashboard';
        } else {
            alert(error || 'Đăng nhập thất bại.');
        }
    } catch (err) {
        alert(err.message);
    }
});
🌐

API Endpoints

Danh sách Endpoints

Method Endpoint Mô tả Auth?
POST /webauthn/register/options Lấy options để đăng ký credential ✅ Yes
POST /webauthn/register Gửi attestation để lưu credential ✅ Yes
POST /webauthn/login/options Lấy options để đăng nhập ❌ Guest
POST /webauthn/login Gửi assertion để xác thực ❌ Guest
🛡️

Bảo mật

Các lớp bảo mật của Passkey

✅ Điểm mạnh:
• Mật mã bất đối xứng (ECDSA/RSA)
• Challenge-Response chống replay attack
• Origin Binding - chỉ hoạt động trên đúng domain
• User Presence - yêu cầu tương tác vật lý
• User Verification - xác thực sinh trắc học
❌ Những điều cần tránh:
• Không lưu Private Key trên server
• Không sử dụng HTTP (phải dùng HTTPS hoặc localhost)
• Không set challenge timeout quá dài (>5 phút)
• Không cho phép đăng ký credential khi chưa xác thực user

Database Schema

Bảng webauthn_credentials lưu trữ:

Column Mô tả
id Credential ID (unique identifier)
user_id Foreign key đến bảng users
public_key Public Key của credential (CBOR encoded)
counter Sign counter để phát hiện credential bị clone