Files
goodgo-platform/docs/security/PAYMENT_SECURITY_CHECKLIST.md
Ho Ngoc Hai 11f2bf26e6
Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 29s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 2m42s
Deploy / Build Web Image (push) Failing after 27s
Deploy / Build AI Services Image (push) Failing after 29s
E2E Tests / Playwright E2E (push) Failing after 43s
Deploy / Build API Image (push) Failing after 1m31s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 6s
Security Scanning / Trivy Scan — API Image (push) Failing after 5m35s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 3m45s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
Security Scanning / Trivy Scan — Web Image (push) Failing after 13m51s
Security Scanning / Trivy Filesystem Scan (push) Failing after 14m46s
Security Scanning / Security Gate (push) Has been cancelled
chore: update project documentation, audit reports, and initialize IDE configuration files
2026-04-19 03:12:54 +07:00

19 KiB

GoodGo Platform - Danh Sách Kiểm Tra Bảo Mật Mô-đun Thanh Toán

Các Tệp Quan Trọng Cần Xem Xét Bảo Mật

🔴 ƯU TIÊN CAO NHẤT (Xem Xét Trước)

1. Xác Minh Chữ Ký Callback

Các tệp:

  • infrastructure/services/vnpay.service.ts (dòng 72-105)
  • infrastructure/services/momo.service.ts (dòng 102-147)
  • infrastructure/services/zalopay.service.ts (dòng 98-144)

Danh sách kiểm tra bảo mật:

  • Xác minh rằng crypto.timingSafeEqual() được sử dụng cho tất cả các so sánh HMAC
  • Xác nhận khóa xác minh chữ ký là chính xác
  • Kiểm tra rằng thuật toán băm khớp với đặc tả của nhà cung cấp (VNPay: SHA512, MoMo/ZaloPay: SHA256)
  • Xác minh rằng việc tái tạo dữ liệu chữ ký khớp chính xác với tài liệu của nhà cung cấp
  • Kiểm tra các kịch bản tấn công phát lại - các callback cũ có bị từ chối không?
  • Xác nhận thứ tự tham số trong chữ ký là đúng
  • Kiểm tra tấn công timing - tất cả các triển khai đều sử dụng so sánh thời gian không đổi
  • Xác minh rằng việc ghi nhật ký rawData không làm lộ dữ liệu chữ ký nhạy cảm

2. Bảo Vệ Race Condition - Callback Thanh Toán

Tệp:

  • application/commands/handle-callback/handle-callback.handler.ts (dòng 32-110)
  • infrastructure/repositories/prisma-payment.repository.ts (dòng 84-109)

Danh sách kiểm tra bảo mật:

  • Xác nhận updateIfStatus() sử dụng mệnh đề WHERE với mảng status IN
  • Xác minh Prisma trả về null khi xảy ra lỗi P2025 một cách đúng đắn
  • Kiểm tra các kịch bản callback đồng thời cho cùng một thanh toán
  • Xác minh phản hồi idempotent cho các thanh toán đã được xử lý
  • Xác nhận rằng sự kiện chỉ được phát một lần cho mỗi callback duy nhất
  • Kiểm tra rằng trạng thái PROCESSING được sử dụng như trạng thái trung gian
  • Xác minh không có race condition giữa kiểm tra null và xuất bản sự kiện

3. Bảo Vệ Race Condition - Thao Tác Ký Quỹ (Escrow)

Các tệp:

  • application/commands/hold-escrow/hold-escrow.handler.ts (dòng 23-67)
  • application/commands/release-escrow/release-escrow.handler.ts (dòng 24-45)

Danh sách kiểm tra bảo mật:

  • NGHIÊM TRỌNG: Không có khóa Redis - các yêu cầu đồng thời có thể gây hỏng trạng thái
  • Kiểm tra xem có nhiều thao tác giữ đồng thời trong nhật ký không
  • Xác minh rằng không có lệnh/ký quỹ nào có thể ở hai trạng thái cùng lúc
  • Kiểm tra: điều gì xảy ra nếu giữ và giải phóng được gọi đồng thời?
  • Kiểm tra: điều gì xảy ra nếu giữ được gọi hai lần liên tiếp nhanh?
  • Triển khai: Khóa phân tán Redis cho các thao tác ký quỹ
  • Tài liệu: Hành vi mong đợi khi truy cập đồng thời

4. Xác Thực Số Tiền Tài Chính

Các tệp:

  • domain/value-objects/money.vo.ts (dòng 1-21)
  • domain/value-objects/platform-fee.vo.ts (dòng 1-31)

Danh sách kiểm tra bảo mật:

  • Xác minh giới hạn tối đa 999_999_999_999 VND được áp dụng
  • Xác nhận số tiền bằng không/âm bị từ chối
  • Kiểm tra: số tiền có thể được đặt thành âm thông qua SQL injection không?
  • Xác minh tính toán phí nền tảng: (amount * 5) / 100 = đúng
  • Kiểm tra: tính toán phí có xử lý làm tròn đúng không?
  • Kiểm tra: trường hợp biên của lệnh 1 VND - phí có đúng không?
  • Xác minh tính toán tiền thanh toán cho người bán: amount - fee ≥ 0
  • Kiểm tra: tiền thanh toán cho người bán có thể âm không?

🟠 ƯU TIÊN CAO

5. Máy Trạng Thái Lệnh/Ký Quỹ

Các tệp:

  • domain/entities/order.entity.ts (dòng 22-32 định nghĩa máy trạng thái)
  • domain/entities/escrow.entity.ts (dòng 74-148 chuyển đổi trạng thái)

Danh sách kiểm tra bảo mật:

  • Xác minh danh sách trắng VALID_TRANSITIONS là đầy đủ và đúng
  • Kiểm tra: có thể xảy ra bất kỳ chuyển đổi không hợp lệ nào không?
  • Kiểm tra: PAYMENT_PENDING → ESCROW_HELD mà không có PAYMENT_CONFIRMED?
  • Xác minh trạng thái DISPUTE có thể chuyển sang ESCROW_RELEASED hoặc REFUNDED
  • Kiểm tra: điều gì xảy ra nếu lệnh cố chuyển sang trạng thái không hợp lệ?
  • Kiểm tra: tất cả các thay đổi trạng thái có được lưu trữ nguyên tử không?
  • Xác minh: các trường dấu thời gian được cập nhật đúng cho mỗi lần chuyển đổi
  • Kiểm tra: callback không theo thứ tự không làm hỏng trạng thái

6. Bảo Vệ Idempotency

Các tệp:

  • application/commands/create-order/create-order.handler.ts (dòng 32-38)
  • application/commands/create-payment/create-payment.handler.ts (handler chưa hiển thị đầy đủ)
  • infrastructure/repositories/prisma-order.repository.ts (dòng 18-22)
  • infrastructure/repositories/prisma-payment.repository.ts (dòng 24-29)

Danh sách kiểm tra bảo mật:

  • Xác minh idempotencyKey là duy nhất theo user/request
  • Kiểm tra: các yêu cầu trùng lặp với cùng khóa trả về cùng lệnh
  • Kiểm tra: các yêu cầu trùng lặp với cùng khóa không bị tính phí hai lần
  • Kiểm tra: idempotencyKey có được lưu trữ trong cơ sở dữ liệu không?
  • Xác minh: ràng buộc duy nhất trên idempotencyKey trong cơ sở dữ liệu
  • Kiểm tra: điều gì xảy ra nếu callback đến trước khi lệnh được tạo?
  • Kiểm tra: điều gì xảy ra nếu thanh toán được tạo nhưng callback bị mất?
  • Kiểm tra: TTL trên các khóa idempotency để tránh phình to

7. Xác Thực Ủy Quyền & Quyền Sở Hữu

Các tệp:

  • presentation/controllers/orders.controller.ts (dòng 44-116)
  • presentation/controllers/payments.controller.ts (dòng 52-139)

Danh sách kiểm tra bảo mật:

  • Xác minh JwtAuthGuard trên tất cả các endpoint người dùng
  • Kiểm tra: người dùng có thể xem lệnh/thanh toán của người dùng khác không?
  • Xác minh: ủy quyền người mua được kiểm tra trong truy vấn lệnh
  • Xác minh: chỉ người bán/người mua mới có thể truy cập giao dịch của họ
  • Kiểm tra: lỗ hổng IDOR - người dùng A truy cập lệnh của người dùng B
  • Kiểm tra: các endpoint chỉ dành cho admin sử dụng RolesGuard
  • Kiểm tra: người dùng không phải admin không thể gọi giữ/giải phóng ký quỹ
  • Xác minh: user.sub (JWT subject) được trích xuất đúng cách

8. Bảo Mật Hoàn Tiền

Các tệp:

  • application/commands/refund-payment/refund-payment.handler.ts (chưa hiển thị đầy đủ)
  • infrastructure/services/vnpay.service.ts (dòng 107-169)
  • infrastructure/services/momo.service.ts (dòng 149-202)
  • infrastructure/services/zalopay.service.ts (dòng 146-197)

Danh sách kiểm tra bảo mật:

  • Chỉ vai trò ADMIN mới có thể khởi tạo hoàn tiền
  • Xác minh: số tiền hoàn tiền ≤ số tiền thanh toán gốc
  • Kiểm tra: số tiền hoàn tiền có thể âm không?
  • Kiểm tra: thanh toán có thể được hoàn tiền nhiều lần không?
  • Xác minh: theo dõi trạng thái hoàn tiền trong thực thể Payment
  • Kiểm tra: xác thực phản hồi hoàn tiền từ nhà cung cấp
  • Kiểm tra: hoàn tiền từng phần - nhiều lần hoàn tiền có được theo dõi không?
  • Xác minh: tiền thực sự được gửi lại cho khách hàng (không phải cho ứng dụng)

9. Giới Hạn Tốc Độ Trên Callback

Tệp:

  • presentation/controllers/payments.controller.ts (dòng 75-89)

Danh sách kiểm tra bảo mật:

  • Xác nhận: decorator @Throttle với 20 yêu cầu trên 60 giây
  • Kiểm tra: @EndpointRateLimit với 100 yêu cầu trên 60 giây
  • Xác minh: khóa giới hạn tốc độ dựa trên IP
  • Kiểm tra: tấn công ngập lụt callback được giảm thiểu?
  • Kiểm tra: bỏ qua admin đã bị vô hiệu hóa cho callback
  • Xác minh: cơ chế lưu trữ giới hạn tốc độ (trong bộ nhớ? Redis?)
  • Kiểm tra: các đợt bùng phát callback hợp lệ (nhà cung cấp thanh toán thử lại)
  • Kiểm tra: lỗi giới hạn tốc độ được ghi nhật ký phù hợp

🟡 ƯU TIÊN TRUNG BÌNH

10. Quản Lý Cấu Hình & Bí Mật

Các tệp:

  • infrastructure/services/vnpay.service.ts (dòng 27-32)
  • infrastructure/services/momo.service.ts (dòng 27-31)
  • infrastructure/services/zalopay.service.ts (dòng 27-30)

Danh sách kiểm tra bảo mật:

  • Xác minh: tất cả bí mật được tải từ ConfigService (không được mã hóa cứng)
  • Kiểm tra: tệp .env có trong .gitignore không
  • Xác nhận: bí mật không được ghi nhật ký ở bất kỳ đâu
  • Xác minh: bí mật băm có độ dài phù hợp (khuyến nghị 32+ ký tự)
  • Kiểm tra: URL sandbox/production được phân tách theo môi trường
  • Kiểm tra: thiếu cấu hình gây ra lỗi sớm (không phải khi thanh toán)
  • Xác minh: cơ chế xoay bí mật tồn tại hoặc được lên kế hoạch
  • Kiểm tra: biến môi trường được mã hóa khi lưu trữ trong CI/CD

11. Ràng Buộc Cơ Sở Dữ Liệu

Các tệp:

  • Kiểm tra schema Prisma cho các mô hình order/escrow/payment

Danh sách kiểm tra bảo mật:

  • Xác minh: ràng buộc duy nhất trên idempotencyKey theo user
  • Kiểm tra: ràng buộc NOT NULL trên các trường quan trọng
  • Xác minh: quan hệ ONE-TO-ONE order ↔ escrow
  • Kiểm tra: ràng buộc khóa ngoại ngăn chặn dữ liệu mồ côi
  • Xác minh: các trường trạng thái có ràng buộc CHECK hoặc enum
  • Kiểm tra: các trường số tiền có kiểu số đúng (không phải chuỗi)
  • Xác minh: không có ID do người dùng cung cấp trực tiếp được sử dụng mà không qua xác thực
  • Kiểm tra: chỉ mục cơ sở dữ liệu trên các trường được truy vấn thường xuyên

12. Xử Lý Lỗi & Tiết Lộ Thông Tin

Các tệp:

  • Tất cả các handler bắt lỗi và ghi nhật ký phù hợp

Danh sách kiểm tra bảo mật:

  • Xác minh: thông báo lỗi không làm lộ dữ liệu nhạy cảm
  • Kiểm tra: stack trace không bị lộ cho client
  • Xác minh: thông báo lỗi chung cho các thao tác thất bại
  • Kiểm tra: mã lỗi được tài liệu hóa (ví dụ: OrderNotFound)
  • Kiểm tra: số tiền không hợp lệ hiển thị lỗi phù hợp
  • Xác minh: callback thất bại được ghi nhật ký với ngữ cảnh nhà cung cấp
  • Kiểm tra: lỗi hoàn tiền không lộ cơ chế thử lại
  • Xác minh: không có truy vấn SQL nào bị lộ trong thông báo lỗi

13. Ghi Nhật Ký & Dấu Vết Kiểm Toán

Các tệp:

  • Tất cả các handler sử dụng logger.log() và logger.error()

Danh sách kiểm tra bảo mật:

  • Xác minh: các thao tác quan trọng được ghi nhật ký (thanh toán, hoàn tiền, thay đổi ký quỹ)
  • Kiểm tra: nhật ký bao gồm ngữ cảnh người dùng (userId, orderId, v.v.)
  • Xác minh: nhật ký bao gồm dấu thời gian và chuyển đổi trạng thái
  • Kiểm tra: không có dữ liệu nhạy cảm nào được ghi nhật ký (bí mật thanh toán, thông tin CC đầy đủ)
  • Xác minh: xoay nhật ký được cấu hình
  • Kiểm tra: nhật ký được bảo vệ khỏi giả mạo (ký/băm)
  • Kiểm tra: dấu vết kiểm toán cho thấy vòng đời lệnh/thanh toán đầy đủ
  • Xác minh: callback không hợp lệ được ghi nhật ký với thông tin chi tiết để điều tra

🟢 ƯU TIÊN THẤP HƠN

14. Độ Bao Phủ Kiểm Thử

Các tệp:

  • application/__tests__/handle-callback-edge-cases.handler.spec.ts (các trường hợp biên)
  • Tất cả các tệp __tests__

Danh sách kiểm tra bảo mật:

  • Kiểm tra: độ bao phủ kiểm thử cho xác minh chữ ký callback
  • Xác minh: kiểm thử cho các kịch bản race condition
  • Kiểm tra: kiểm thử cho các trường hợp biên idempotency
  • Xác minh: kiểm thử cho các chuyển đổi trạng thái không hợp lệ
  • Kiểm tra: kiểm thử cho các lỗi ủy quyền
  • Xác minh: kiểm thử cho các thao tác ký quỹ đồng thời
  • Kiểm tra: kiểm thử cho các trường hợp biên xác thực số tiền
  • Xác minh: kiểm thử cho các kịch bản nhà cung cấp thất bại

15. Tài Liệu API

Các tệp:

  • Các decorator của Controller (@ApiOperation, @ApiResponse)

Danh sách kiểm tra bảo mật:

  • Xác minh: các endpoint được tài liệu hóa với các yêu cầu bảo mật
  • Kiểm tra: schema phản hồi không bao gồm bí mật
  • Xác minh: giới hạn tốc độ được tài liệu hóa
  • Kiểm tra: yêu cầu ủy quyền được nêu rõ ràng
  • Xác minh: các phản hồi lỗi được tài liệu hóa
  • Kiểm tra: xác minh chữ ký webhook được giải thích
  • Xác minh: hành vi thử lại callback được tài liệu hóa
  • Kiểm tra: sự khác biệt hành vi theo từng nhà cung cấp được ghi chú

Các Kịch Bản Tấn Công Cần Kiểm Thử

Kịch Bản 1: Ngập Lụt Callback

Tấn công: Gửi 1000 callback mỗi giây
Mong đợi: Bộ giới hạn tốc độ chặn sau 100 trên 60 giây
Mong đợi: Trạng thái thanh toán không thay đổi sau callback thành công đầu tiên
Kiểm tra: Không bị tính phí hai lần

Kịch Bản 2: Tấn Công Phát Lại

Tấn công: Gửi lại callback thành công cũ
Mong đợi: Thanh toán đã ở trạng thái cuối cùng, phản hồi idempotent
Mong đợi: Không bị tính phí hai lần
Kiểm tra: Nhật ký cho thấy lần thử phát lại

Kịch Bản 3: Giải Phóng Ký Quỹ Đồng Thời

Tấn công: Gọi /orders/{id}/escrow/release hai lần đồng thời
Mong đợi: Một thành công, một thất bại với ESCROW_INVALID_STATE
Rủi ro hiện tại: ⚠️ Có thể thành công hai lần nếu không có khóa Redis

Kịch Bản 4: Callback Giả Mạo

Tấn công: Gửi callback với chữ ký HMAC không hợp lệ
Mong đợi: Ngoại lệ xác thực, thanh toán bị từ chối
Kiểm tra: Xác minh chữ ký sử dụng so sánh thời gian không đổi

Kịch Bản 5: Mất Đồng Bộ Trạng Thái Lệnh/Ký Quỹ

Tấn công: Lệnh ở trạng thái PAYMENT_CONFIRMED, Ký quỹ ở trạng thái RELEASED
Mong đợi: Trạng thái máy không hợp lệ - không nên xảy ra
Kiểm tra: Cập nhật lệnh + ký quỹ có nguyên tử không?

Kịch Bản 6: Tràn Số Nguyên

Tấn công: Gửi thanh toán cho 999_999_999_999 VND
Mong đợi: Money VO từ chối (giới hạn tối đa)
Tấn công: Gửi tính toán phí cho số tiền lớn
Mong đợi: Không tràn số nguyên, phí 5% được tính đúng

Kịch Bản 7: Bỏ Qua Ủy Quyền

Tấn công: Lấy ID lệnh của người dùng khác, gọi /orders/{theirID}
Mong đợi: 404 hoặc Forbidden (không tìm thấy để ngăn chặn liệt kê)
Kiểm tra: Quyền sở hữu được xác minh trong query handler

Kịch Bản 8: Hoàn Tiền Hai Lần

Tấn công: Gọi /payments/{id}/refund hai lần
Mong đợi: Lần gọi thứ hai thất bại (thanh toán đã REFUNDED)
Kiểm tra: Máy trạng thái ngăn chặn chuyển đổi không hợp lệ

Số Liệu Bảo Mật

Số liệu Trạng thái Mục tiêu
Tất cả callback xác minh chữ ký HMAC 100%
Race condition được bảo vệ bằng khóa/nguyên tử ⚠️ TỪNG PHẦN 100% (các thao tác ký quỹ cần khóa)
Khóa idempotency được áp dụng 100%
Ủy quyền trên tất cả endpoint 100%
Xác thực số tiền (min/max) 100%
Giới hạn tốc độ trên callback 100%
Thông báo lỗi không làm lộ bí mật ⚠️ CẦN XEM XÉT 100%
Ghi nhật ký dấu vết kiểm toán 100%
Độ bao phủ kiểm thử bảo mật ⚠️ TỪNG PHẦN >80%
Ràng buộc cơ sở dữ liệu ⚠️ CẦN XÁC MINH 100%

Các Hành Động Được Khuyến Nghị

NGHIÊM TRỌNG (Thực Hiện Trước Khi Đưa Lên Sản Xuất)

  1. Triển khai khóa phân tán Redis cho các thao tác giữ/giải phóng ký quỹ

    • Sử dụng @nestjs/common hoặc dịch vụ khóa bên ngoài
    • Ngăn chặn các đột biến trạng thái đồng thời
  2. Thêm xác thực ràng buộc cơ sở dữ liệu

    • Xác minh schema Prisma có các ràng buộc phù hợp
    • Thêm chỉ mục duy nhất trên (userId, idempotencyKey)
  3. Kiểm toán tất cả thông báo lỗi

    • Đảm bảo không có bí mật nào bị rò rỉ trong phản hồi
    • Kiểm tra thủ công các trường hợp lỗi

CAO (Trước Lần Triển Khai Đầu Tiên)

  1. Thêm bộ kiểm thử toàn diện

    • Kiểm thử race condition
    • Kiểm thử phát lại callback
    • Kiểm thử IDOR
  2. Kiểm toán bí mật

    • Xác minh không có giá trị được mã hóa cứng
    • Kiểm tra .env/.gitignore
    • Tài liệu quy trình xoay bí mật
  3. Kiểm thử tải callback

    • Mô phỏng các đợt thử lại từ nhà cung cấp
    • Xác minh giới hạn tốc độ hoạt động

TRUNG BÌNH (Ngắn Hạn)

  1. Thêm ghi nhật ký kiểm toán chi tiết hơn

    • Chuyển đổi trạng thái thanh toán
    • Các lần thử callback thất bại
    • Yêu cầu/phê duyệt hoàn tiền
  2. Tạo sổ tay ứng phó sự cố

    • Phát hiện thanh toán trùng lặp
    • Phục hồi lệnh bị kẹt
    • Vấn đề tích hợp nhà cung cấp

TỐT NẾU CÓ

  1. Mã hóa cấp trường cho dữ liệu nhạy cảm

    • Dữ liệu callback thanh toán
    • ID giao dịch của nhà cung cấp
  2. Giám sát xác minh chữ ký webhook

    • Cảnh báo khi xác minh thất bại
    • Theo dõi các lần thử phát lại của nhà cung cấp