CYBERSOFT
Đăng nhập

Thực chiến Fintech: nạp tiền, hạn mức KYC & chống gian lận

Thực chiến doanh nghiệpFintechPlaywrightAPIThực tếPhỏng vấn
🗓 1 tháng trước21 phút đọc·👁 1,027 lượt xem👤 199 người đọc

Oracle-first cho fintech: bảo toàn số dư qua sổ cái ghi kép, hạn mức theo tầng KYC thực thi ở backend, idempotency nạp tiền, luật fraud velocity/geo/device, và đối soát với đối tác. Playwright + request context để seed KYC, bơm sự kiện fraud, kiểm ledger cân bằng, xử lý timeout/webhook, CI phân tầng bảo mật dữ liệu và ranh giới AI-agent four-eyes. Kèm góc phỏng vấn.

1. Bối cảnh nghiệp vụ: ví điện tử là hệ thống tiền thật

Một ví điện tử hay ứng dụng fintech xử lý tiền thật, nên sai sót không chỉ gây khó chịu mà tạo thiệt hại tài chính và rủi ro pháp lý. Ở quy mô năm triệu người dùng, mỗi ngày có hàng trăm nghìn lệnh nạp tiền, và mỗi lệnh phải tuân thủ quy định chống rửa tiền, hạn mức theo mức độ định danh khách hàng, và các luật chống gian lận. Ba trục kiểm thử cốt lõi là: nạp tiền phải bảo toàn số dư và idempotent, hạn mức theo tầng KYC phải được thực thi ở backend, và các luật fraud dựa trên tốc độ giao dịch, vị trí địa lý và thiết bị phải chặn được hành vi bất thường mà không cản khách thật.

Bài viết này áp dụng nguyên tắc oracle-first cho fintech: thay vì khẳng định 'nạp thành công', ta khẳng định các bất biến tài chính. Chúng ta sẽ định nghĩa mô hình ledger kiểu ghi kép làm oracle bảo toàn tiền, dựng bảng hạn mức theo tầng KYC, viết test plan và ma trận ca, rồi đi sâu vào các ca thất bại: idempotency khi retry nạp tiền, vượt hạn mức, các luật fraud, và đối soát với đối tác thanh toán. Playwright kết hợp request context cho phép seed tầng KYC, bơm chuỗi sự kiện fraud và kiểm sổ cái cân bằng, tất cả một cách tất định.

Quy mô giả định: 5 triệu người dùng, hàng trăm nghìn lệnh nạp/ngày, tuân thủ AML/KYC theo quy định ngân hàng nhà nước, đối soát T+1 với đối tác thanh toán.
LUỒNG NẠP TIỀN · KYC · FRAUD Top-up requestidempotency key KYC gatetier → hạn mức Fraud enginevelocity/geo/device Ledgerdouble-entry Partner reconđối soát cuối ngày Oracle: bảo toàn số dư · hạn mức KYC · idempotent top-up · luật fraud · khớp đối soát Playwright + request context: seed KYC tier, bơm sự kiện fraud, kiểm ledger cân bằng.
Luồng nạp tiền qua KYC, fraud engine, ledger và đối soát với đối tác.

2. Ledger ghi kép: bất biến bảo toàn tiền làm oracle

Trái tim của mọi hệ thống tiền tệ đáng tin là sổ cái ghi kép. Mỗi giao dịch tạo ít nhất hai bút toán cân bằng nhau: một bên ghi nợ, một bên ghi có, và tổng của mọi bút toán trong hệ thống luôn bằng không. Đây là bất biến bảo toàn tiền mạnh nhất và là oracle vàng cho kiểm thử fintech. Khi khách nạp một triệu đồng, tài khoản ví khách tăng một triệu và tài khoản quỹ đối tác giảm một triệu tương ứng; tiền không tự sinh ra hay biến mất. Test không kiểm 'số dư hiển thị đúng' mà kiểm 'tổng ghi nợ bằng tổng ghi có' và 'không có bút toán mồ côi'.

sql
-- Sổ cái ghi kép: mỗi giao dịch phải cân bằng, không đâu tiền tự sinh
CREATE TABLE ledger_entry (
  id             UUID PRIMARY KEY,
  txn_id         UUID NOT NULL,            -- gom các bút toán của cùng 1 giao dịch
  account_id     BIGINT NOT NULL,
  direction      TEXT NOT NULL CHECK (direction IN ('DEBIT','CREDIT')),
  amount         BIGINT NOT NULL CHECK (amount > 0),  -- số nguyên, đơn vị nhỏ nhất
  created_at     TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- ORACLE bảo toàn tiền: với MỌI txn_id, tổng DEBIT = tổng CREDIT
--   SELECT txn_id,
--          SUM(CASE WHEN direction='DEBIT'  THEN amount ELSE 0 END) AS d,
--          SUM(CASE WHEN direction='CREDIT' THEN amount ELSE 0 END) AS c
--   FROM ledger_entry GROUP BY txn_id HAVING d <> c;   -- phải trả về 0 hàng

CREATE TABLE top_up (
  id              UUID PRIMARY KEY,
  user_id         BIGINT NOT NULL,
  amount          BIGINT NOT NULL,
  idempotency_key TEXT UNIQUE NOT NULL,    -- BẤT BIẾN: 1 key → 1 lần cộng tiền
  status          TEXT NOT NULL            -- PENDING | SUCCEEDED | FAILED
);

Với tester, sổ cái ghi kép biến việc kiểm tiền thành một truy vấn đơn giản mà cực mạnh: nhóm các bút toán theo giao dịch, kiểm tổng ghi nợ bằng tổng ghi có ở mọi giao dịch. Nếu có một giao dịch lệch, đó là bằng chứng tiền bị tạo hoặc mất ở đâu đó. Một bất biến toàn cục nữa là tổng số dư của mọi tài khoản khách cộng lại phải bằng tổng tiền đối tác đã chuyển vào, trừ phí. Những truy vấn này chính là oracle: chúng không quan tâm giao diện hiển thị gì, chỉ quan tâm sổ cái có cân bằng hay không.

💡 Thêm một 'oracle test' chạy sau mỗi kịch bản: truy vấn toàn sổ cái để chắc mọi giao dịch cân bằng. Nó bắt được lỗi rò rỉ tiền mà các assert lẻ bỏ sót.

3. Hạn mức theo tầng KYC: đặc tả thành bảng quyết định

KYC là quy trình định danh khách hàng, và mức độ định danh quyết định hạn mức giao dịch. Khách chưa xác minh chỉ được nạp một khoản nhỏ; khách đã nộp giấy tờ tuỳ thân được hạn cao hơn; khách xác minh nâng cao gồm địa chỉ và nguồn tiền được hạn cao nhất. Đây là yêu cầu tuân thủ bắt buộc, không phải tuỳ chọn giao diện. Sai lầm phổ biến là chỉ ẩn nút trên giao diện khi vượt hạn, còn backend vẫn chấp nhận — một kẻ tấn công gọi thẳng API sẽ vượt qua. Vì thế oracle phải kiểm ở backend: tổng nạp trong hai mươi tư giờ không được vượt hạn mức của tầng hiện tại.

HẠN MỨC THEO TẦNG KYC · KYC-TIER LIMITS Tầng Hạn mức/ngày Điều kiện Tier 0 · chưa KYC2.000.000₫chỉ email Tier 1 · CMND/CCCD20.000.000₫giấy tờ + selfie Tier 2 · địa chỉ + nguồn tiền200.000.000₫xác minh nâng cao Vượt hạn mức phải bị TỪ CHỐI ở backend, không chỉ ẩn nút trên UI. Oracle: SUM(top-up trong 24h) ≤ hạn mức của tier hiện tại.
Bảng hạn mức theo tầng KYC làm oracle cho kiểm thử.
ts
import { test, expect } from './fixtures';

// data-driven: mỗi tầng KYC có hạn mức riêng — kiểm ở BACKEND, không phải UI
const tiers = [
  { tier: 0, limit: 2_000_000,   amount: 2_500_000, expect: 'DENIED'  },  // vượt → từ chối
  { tier: 0, limit: 2_000_000,   amount: 1_500_000, expect: 'ALLOWED' },
  { tier: 1, limit: 20_000_000,  amount: 25_000_000, expect: 'DENIED'  },
  { tier: 2, limit: 200_000_000, amount: 150_000_000, expect: 'ALLOWED' },
];

for (const t of tiers) {
  test(`tier ${t.tier} nạp ${t.amount} phải ${t.expect}`, async ({ request }) => {
    // seed người dùng với đúng tầng KYC qua test-only API
    const user = await (await request.post('/api/test/users', { data: { kycTier: t.tier } })).json();

    const res = await request.post('/api/topups', {
      data: { userId: user.id, amount: t.amount, key: crypto.randomUUID() },
    });

    // ORACLE: vượt hạn mức tier → backend trả 403, KHÔNG cộng tiền
    if (t.expect === 'DENIED') {
      expect(res.status()).toBe(403);
      const wallet = await (await request.get(`/api/test/wallets/${user.id}`)).json();
      expect(wallet.balance).toBe(0);   // số dư không đổi khi bị từ chối
    } else {
      expect(res.status()).toBe(201);
    }
  });
}
🎯 Bypass hạn mức bằng cách gọi thẳng API

Một fintech kiểm hạn mức chỉ ở phía giao diện: khi vượt, nút nạp bị mờ đi. Đội bảo mật thử gọi thẳng endpoint nạp tiền bằng công cụ API và nạp được gấp mười lần hạn mức, vì backend không kiểm lại. Đây là lỗ hổng tuân thủ nghiêm trọng có thể bị cơ quan quản lý phạt. Đội khắc phục bằng cách chuyển toàn bộ kiểm hạn mức xuống backend và thêm ca test gọi thẳng API vượt hạn phải nhận 403. Bài học: mọi ràng buộc tuân thủ phải thực thi ở backend, giao diện chỉ là lớp tiện lợi.

🔒

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!