CYBERSOFT
Đăng nhập

WebAuthn passkeys & Web Storage API testing (Playwright 1.61)

Chuyên công nghệNgân hàngPlaywrightSecurityThực tếNâng cao
🗓 1 tháng trước21 phút đọc·👁 1,498 lượt xem👤 204 người đọc

Kiểm thử passkey/2FA bằng WebAuthn virtual authenticator không cần thiết bị thật, soi client qua page.localStorage trực tiếp, video retention cho test flaky, per-error reporting, và một ví dụ oracle đăng nhập passkey ngân hàng kèm góc phỏng vấn.

1. Vì sao passkey trở thành bài toán kiểm thử của ngân hàng

Passkey là chuẩn đăng nhập không mật khẩu dựa trên WebAuthn: thay vì gõ mật khẩu, người dùng xác thực bằng khoá riêng lưu trên thiết bị (vân tay, Face ID, khoá bảo mật). Với ngân hàng, passkey giảm mạnh rủi ro lừa đảo và nhồi thông tin đăng nhập, nên nhiều tổ chức đang chuyển sang bắt buộc passkey cho 2FA hoặc đăng nhập chính. Nhưng điều này đặt ra bài toán kiểm thử hóc búa: làm sao test luồng đăng nhập passkey một cách tự động, lặp lại được, mà không cần vân tay thật hay thiết bị vật lý? Playwright 1.61 trả lời bằng WebAuthn virtual authenticator.

  • Passkey dùng cặp khoá công khai/riêng, khoá riêng không rời thiết bị.
  • Không có mật khẩu để đánh cắp hay nhồi — chống phishing tốt hơn.
  • Ngân hàng bắt buộc passkey cho giao dịch giá trị cao hoặc đổi thông tin.
  • Thách thức test: tự động hoá xác thực sinh trắc mà không có thiết bị thật.
WebAuthn dùng challenge-response ký số: server gửi thử thách ngẫu nhiên, thiết bị ký bằng khoá riêng, server xác minh bằng khoá công khai đã đăng ký. Không có bí mật chia sẻ nào truyền qua mạng, đó là lý do nó chống phishing.

2. WebAuthn virtual authenticator: khái niệm cốt lõi

Virtual authenticator là một trình xác thực WebAuthn ảo do trình duyệt cung cấp qua giao thức CDP, cho phép test tạo passkey trong bộ nhớ và ký thử thách như một thiết bị thật, nhưng hoàn toàn bằng phần mềm. Playwright 1.61 gói tính năng này thành API tiện dụng. Bạn khai báo loại authenticator (ctap2 cho khoá bảo mật, internal cho sinh trắc gắn máy), giao thức truyền (usb, nfc, internal), và các cờ như userVerified hay hasResidentKey. Từ đó, khi trang gọi navigator.credentials.create hay get, trình duyệt dùng authenticator ảo để đáp ứng, không hề bật hộp thoại sinh trắc thật.

Test (Playwright) addVirtualAuthenticator ctap2 · internal · uv Virtual Authenticator passkey (private key) Banking WebApp navigator.credentials .get() → assertion verify chữ ký
Luồng passkey: test cấu hình authenticator ảo → ký thử thách → ngân hàng xác minh chữ ký.
typescript
// Bật WebAuthn virtual authenticator (Playwright 1.61)
import { test, expect } from '@playwright/test';

test('đăng nhập bằng passkey', async ({ page }) => {
  // Tạo trình xác thực ảo qua CDP session
  const client = await page.context().newCDPSession(page);
  await client.send('WebAuthn.enable');
  const { authenticatorId } = await client.send('WebAuthn.addVirtualAuthenticator', {
    options: {
      protocol: 'ctap2',
      transport: 'internal',
      hasResidentKey: true,
      hasUserVerification: true,
      isUserVerified: true,        // giả lập vân tay/Face ID đã xác minh
      automaticPresenceSimulation: true,
    },
  });
  await page.goto('/login');
  await page.getByRole('button', { name: 'Đăng nhập bằng passkey' }).click();
  await expect(page.getByTestId('dashboard')).toBeVisible();
});
💡 Đặt isUserVerified=true và automaticPresenceSimulation=true để authenticator tự 'chạm' và 'xác minh' khi trang yêu cầu, giúp luồng chạy không cần tương tác vật lý. Muốn test đường thất bại, đặt isUserVerified=false rồi khẳng định app từ chối.

3. Đăng ký passkey mới (registration) trong test

Trước khi test đăng nhập, ứng dụng phải có ít nhất một passkey đã đăng ký cho tài khoản. Có hai cách: một là để chính test thực hiện luồng đăng ký (gọi navigator.credentials.create thông qua UI), authenticator ảo sẽ tự tạo và lưu credential; hai là chèn sẵn credential vào authenticator qua lệnh addCredential nếu bạn muốn tách bước đăng ký khỏi test đăng nhập. Cách đầu kiểm được cả luồng đăng ký end-to-end; cách sau nhanh và cô lập hơn khi bạn chỉ quan tâm tới đăng nhập. Cả hai đều không cần thiết bị thật.

typescript
// Cách 1: chạy luồng đăng ký qua UI, authenticator ảo tự lưu credential
test('đăng ký passkey rồi đăng nhập lại', async ({ page }) => {
  const client = await page.context().newCDPSession(page);
  await client.send('WebAuthn.enable');
  await client.send('WebAuthn.addVirtualAuthenticator', {
    options: { protocol: 'ctap2', transport: 'internal',
               hasResidentKey: true, hasUserVerification: true, isUserVerified: true },
  });
  await page.goto('/settings/security');
  await page.getByRole('button', { name: 'Thêm passkey' }).click();
  await expect(page.getByText('Passkey đã được tạo')).toBeVisible();

  // Đăng xuất rồi đăng nhập lại bằng passkey vừa tạo
  await page.getByRole('button', { name: 'Đăng xuất' }).click();
  await page.getByRole('button', { name: 'Đăng nhập bằng passkey' }).click();
  await expect(page.getByTestId('dashboard')).toBeVisible();
});

Nên test đăng ký và đăng nhập passkey trong cùng một test hay tách ra?

Tuỳ mục tiêu. Có một test end-to-end đi qua cả đăng ký lẫn đăng nhập để chứng minh luồng thật liền mạch. Nhưng cho các test đăng nhập biến thể (thất bại, đổi thiết bị, khoá bị thu hồi), hãy chèn sẵn credential để cô lập, tránh phụ thuộc vào bước đăng ký và giữ test nhanh, ổn định.

🔒

Nội dung bị khoá

Bạn đang xem bản xem trước. Đăng nhập để mở khoá toàn bộ bài viết và tất cả tài liệu Tester/QA.

Đã xem 24% nội dung
  • Đọc trọn vẹn mọi bài viết
  • Lưu bài & ghi chú cá nhân
  • Theo dõi tiến độ đã đọc
  • Luyện phỏng vấn, ISTQB, Mock
Đăng nhập để đọc tiếp

Chưa có mã? Lấy mã qua Fanpage / Zalo CyberSoft.

0

💬 Bình luận (0)

Bạn có thể đọc mọi bình luận. Đăng nhập để bình luận

Chưa có bình luận nào. Hãy là người đầu tiên!