Files
goodgo-platform/docs/security/PAYMENT_MODULE_SECURITY_REVIEW.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

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

Tổng Quan

Danh sách file toàn diện cho đợt kiểm tra bảo mật các thực thể Order & Escrow trong module thanh toán. Vị trí: /Users/velikho/Desktop/WORKING/goodgo-platform-ai/apps/api/src/modules/payments/


1. TẦNG DOMAIN - CÁC THỰC THỂ

Các Thực Thể Cốt Lõi

File Mô tả
domain/entities/order.entity.ts THỰC THỂ ORDER - Quản lý vòng đời đơn hàng với máy trạng thái (CREATED→PAYMENT_PENDING→PAYMENT_CONFIRMED→ESCROW_HELD→SHIPPED→DELIVERED→ESCROW_RELEASED→COMPLETED). Xác thực các chuyển trạng thái. Phát sự kiện: OrderCreatedEvent, OrderPaidEvent, OrderCancelledEvent. Các trường quan trọng: buyerId, sellerId, listingId, amount (Money VO), platformFee, sellerPayout.
domain/entities/escrow.entity.ts THỰC THỂ ESCROW - Quản lý vòng đời escrow (PENDING→HELD→RELEASED/DISPUTED/REFUNDED). Lưu trữ số tiền escrow, phí và netPayout đã tính. Phát: EscrowHeldEvent, EscrowReleasedEvent, EscrowDisputedEvent. Xác thực chuyển trạng thái.
domain/entities/payment.entity.ts THỰC THỂ PAYMENT - Quản lý giao dịch thanh toán (PENDING→PROCESSING→COMPLETED/FAILED/REFUNDED). Lưu trữ userId, provider (VNPAY/MOMO/ZALOPAY), type, amount, callbackData, idempotencyKey. Phát: PaymentCreatedEvent, PaymentCompletedEvent, PaymentFailedEvent, PaymentRefundedEvent.

Các Value Object

File Mô tả
domain/value-objects/money.vo.ts VALUE OBJECT MONEY - Bọc các số tiền dưới dạng bigint theo VND. Xác thực: amount > 0, giới hạn tối đa 999_999_999_999. Dùng cho tất cả các số tiền tài chính.
domain/value-objects/platform-fee.vo.ts VALUE OBJECT PHÍ NỀN TẢNG - Tính phí nền tảng 5%. Các phương thức: fromOrderAmount() (tự động tính 5%), create() (số tiền tường minh). Xác thực fee >= 0.

2. TẦNG DOMAIN - REPOSITORY (Giao Diện)

File Mô tả
domain/repositories/order.repository.ts GIAO DIỆN ORDER REPOSITORY - Định nghĩa các phương thức CRUD + truy vấn: findById, findByIdempotencyKey, findByBuyerId, findBySellerId, save, update. Bảo vệ idempotency.
domain/repositories/escrow.repository.ts GIAO DIỆN ESCROW REPOSITORY - Định nghĩa: findById, findByOrderId, save, update. Quan hệ một escrow trên một order.
domain/repositories/payment.repository.ts GIAO DIỆN PAYMENT REPOSITORY - Định nghĩa: findById, findByProviderTxId, findByIdempotencyKey, findByUserId, save, update, updateIfStatus (cập nhật có điều kiện nguyên tử để xử lý race condition).

3. TẦNG DOMAIN - SỰ KIỆN

File Mô tả
domain/events/order-created.event.ts Phát khi tạo order - chứa orderId, buyerId, sellerId, listingId, amount
domain/events/order-paid.event.ts Phát khi thanh toán được xác nhận - chứa orderId, buyerId, amount
domain/events/order-cancelled.event.ts Phát khi order bị hủy - chứa orderId, buyerId, sellerId
domain/events/escrow-held.event.ts Phát khi escrow được giữ - chứa escrowId, orderId, amount
domain/events/escrow-released.event.ts Phát khi escrow được giải phóng - chứa escrowId, orderId, netPayout
domain/events/escrow-disputed.event.ts Phát khi escrow bị tranh chấp - chứa escrowId, orderId, reason
domain/events/payment-created.event.ts Phát khi tạo thanh toán - chứa paymentId, userId, provider, amount
domain/events/payment-completed.event.ts Phát khi thanh toán hoàn tất - chứa paymentId, userId, provider
domain/events/payment-failed.event.ts Phát khi thanh toán thất bại - chứa paymentId, userId, provider
domain/events/payment-refunded.event.ts Phát khi thanh toán được hoàn tiền - chứa paymentId, userId, provider, amount

4. TẦNG CƠ SỞ HẠ TẦNG - REPOSITORY (Triển Khai)

File Mô tả
infrastructure/repositories/prisma-order.repository.ts TRIỂN KHAI ORDER REPOSITORY - Triển khai Prisma ORM. Lưu trữ: id, buyerId, sellerId, listingId, status, amountVND, platformFeeVND, sellerPayoutVND, idempotencyKey, metadata. Xử lý lưu trữ order.
infrastructure/repositories/prisma-escrow.repository.ts TRIỂN KHAI ESCROW REPOSITORY - Triển khai Prisma ORM. Lưu trữ: id, orderId, amountVND, feeVND, status, heldAt, releasedAt, disputeReason, disputedAt. Xử lý lưu trữ escrow.
infrastructure/repositories/prisma-payment.repository.ts TRIỂN KHAI PAYMENT REPOSITORY - Prisma ORM. Lưu trữ: id, userId, transactionId, provider, type, amountVND, status, providerTxId, callbackData, idempotencyKey. QUAN TRỌNG: updateIfStatus() sử dụng mệnh đề WHERE có điều kiện để ngăn race condition nguyên tử (Dòng 84-109).

5. TẦNG CƠ SỞ HẠ TẦNG - DỊCH VỤ CỔNG THANH TOÁN

Giao Diện Cổng Thanh Toán

File Mô tả
infrastructure/services/payment-gateway.interface.ts GIAO DIỆN GATEWAY - Định nghĩa hợp đồng IPaymentGateway: createPaymentUrl(), verifyCallback(), refund(). CallbackVerifyResult bao gồm: isValid, orderId, providerTxId, isSuccess, rawData. Nhạy cảm về bảo mật.

Dịch Vụ VNPay

File Mô tả
infrastructure/services/vnpay.service.ts CỔNG THANH TOÁN VNPAY - Triển khai IPaymentGateway. XÁC MINH CALLBACK (Dòng 72-105): Trích xuất secure hash, loại bỏ khỏi dữ liệu, sắp xếp các tham số, tạo HMAC-SHA512, dùng crypto.timingSafeEqual() để so sánh thời gian cố định. Số tiền nhân 100 cho VND cents. Trả về isValid, orderId (vnp_TxnRef), providerTxId (vnp_TransactionNo), isSuccess (responseCode === '00'). Hỗ trợ hoàn tiền.

Dịch Vụ MoMo

File Mô tả
infrastructure/services/momo.service.ts CỔNG THANH TOÁN MOMO - Triển khai IPaymentGateway. XÁC MINH CALLBACK (Dòng 102-147): Trích xuất chữ ký từ dữ liệu, xây dựng lại chữ ký thô với accessKey, amount, extraData, IPN/redirect URLs, orderId, v.v. Dùng HMAC-SHA256, so sánh thời gian cố định qua crypto.timingSafeEqual(). Kiểm tra thành công: resultCode === '0'. Hỗ trợ hoàn tiền. Amount dưới dạng Number (không phải bigint trong API).

Dịch Vụ ZaloPay

File Mô tả
infrastructure/services/zalopay.service.ts CỔNG THANH TOÁN ZALOPAY - Triển khai IPaymentGateway. XÁC MINH CALLBACK (Dòng 98-144): Dữ liệu được truyền dưới dạng chuỗi JSON trong trường 'data'. MAC được xác minh qua HMAC-SHA256 với key2. Phân tích dữ liệu JSON để trích xuất app_trans_id và zp_trans_id. LƯU Ý BẢO MẬT: Xử lý lỗi phân tích JSON một cách duyên dáng. Dùng so sánh thời gian cố định. Hỗ trợ hoàn tiền (key1).

Factory Cổng Thanh Toán

File Mô tả
infrastructure/services/payment-gateway.factory.ts GATEWAY FACTORY - Trả về instance gateway phù hợp (VNPay/MoMo/ZaloPay) dựa trên enum provider.

6. TẦNG ỨNG DỤNG - COMMAND

Các Order Command

File Mô tả
application/commands/create-order/create-order.command.ts CREATE ORDER COMMAND - Đầu vào: buyerId, sellerId, listingId, amountVND, idempotencyKey. Đối tượng payload.
application/commands/create-order/create-order.handler.ts CREATE ORDER HANDLER - Kiểm tra idempotency qua findByIdempotencyKey. Xác thực amount (Money VO). Tính phí nền tảng (5%) và seller payout. Tạo OrderEntity + EscrowEntity (trạng thái PENDING). Lưu cả hai. Phát sự kiện.
application/commands/cancel-order/cancel-order.command.ts CANCEL ORDER COMMAND - Đầu vào: orderId, userId, reason.
application/commands/cancel-order/cancel-order.handler.ts CANCEL ORDER HANDLER - Xác minh người dùng sở hữu order, xác thực chuyển trạng thái qua entity.markCancelled(), lưu, phát sự kiện.

Các Escrow Command

File Mô tả
application/commands/hold-escrow/hold-escrow.command.ts HOLD ESCROW COMMAND - Đầu vào: orderId. Chỉ dành cho Admin.
application/commands/hold-escrow/hold-escrow.handler.ts HOLD ESCROW HANDLER (Dòng 23-67) - Lấy order + escrow theo orderId. Gọi escrow.hold() để chuyển trạng thái. Cập nhật cả hai thực thể. Phát EscrowHeldEvent. LƯU Ý BẢO MẬT: Không có Redis lock - tiềm ẩn race condition nếu có nhiều yêu cầu đồng thời.
application/commands/release-escrow/release-escrow.command.ts RELEASE ESCROW COMMAND - Đầu vào: orderId. Chỉ dành cho Admin.
application/commands/release-escrow/release-escrow.handler.ts RELEASE ESCROW HANDLER (Dòng 24-45) - Lấy order + escrow theo orderId. Gọi escrow.release() để chuyển trạng thái. Cập nhật cả hai thực thể. Phát EscrowReleasedEvent với netPayout. LƯU Ý BẢO MẬT: Không có Redis lock - tiềm ẩn race condition.

Các Payment Command

File Mô tả
application/commands/create-payment/create-payment.command.ts CREATE PAYMENT COMMAND - Đầu vào: userId, provider, type, amountVND, description, returnUrl, ipAddress, transactionId, idempotencyKey.
application/commands/create-payment/create-payment.handler.ts CREATE PAYMENT HANDLER - Kiểm tra idempotency. Xác thực amount (Money VO). Lấy payment gateway. Gọi createPaymentUrl(). Tạo PaymentEntity (trạng thái PENDING). Lưu. Phát PaymentCreatedEvent. Trả về paymentUrl để frontend chuyển hướng.
application/commands/refund-payment/refund-payment.command.ts REFUND PAYMENT COMMAND - Đầu vào: paymentId, reason, userId. Lệnh dành cho Admin.
application/commands/refund-payment/refund-payment.handler.ts REFUND PAYMENT HANDLER - Xác minh thanh toán tồn tại, gọi gateway.refund() với các tham số đặc thù nhà cung cấp, cập nhật trạng thái thanh toán thành REFUNDED, phát PaymentRefundedEvent.

Handler Callback (QUAN TRỌNG)

File Mô tả
application/commands/handle-callback/handle-callback.command.ts HANDLE CALLBACK COMMAND - Đầu vào: provider (enum PaymentProvider), callbackData (Record<string, string>).
application/commands/handle-callback/handle-callback.handler.ts HANDLE CALLBACK HANDLER (Dòng 32-110) - FILE BẢO MẬT QUAN TRỌNG. Lấy gateway, gọi verifyCallback() (xác thực chữ ký). Nếu không hợp lệ: ném ValidationException. Nếu hợp lệ: Dùng paymentRepo.updateIfStatus() với WHERE có điều kiện ['PENDING', 'PROCESSING'] (Dòng 48-55) - cập nhật nguyên tử để ngăn xử lý trùng lặp. Nếu cập nhật trả về null: kiểm tra xem thanh toán có tồn tại không (đã xử lý - phản hồi idempotent). Nếu thành công: gọi payment.emitCompleted(), ngược lại payment.emitFailed(). Phát sự kiện. BẢO VỆ RACE CONDITION MẠNH qua cập nhật có điều kiện.

7. TẦNG ỨNG DỤNG - QUERY

File Mô tả
application/queries/get-order-status/get-order-status.query.ts Query: Đầu vào orderId, userId (để phân quyền).
application/queries/get-order-status/get-order-status.handler.ts Lấy order, xác minh quyền sở hữu (buyer/seller), trả về trạng thái + chi tiết.
application/queries/get-payment-status/get-payment-status.query.ts Query: Đầu vào paymentId, userId.
application/queries/get-payment-status/get-payment-status.handler.ts Lấy thanh toán, xác minh quyền sở hữu, trả về trạng thái + chi tiết.
application/queries/list-transactions/list-transactions.query.ts Query: Đầu vào userId, status (tùy chọn), limit, offset.
application/queries/list-transactions/list-transactions.handler.ts Liệt kê các thanh toán của người dùng với phân trang, lọc theo status nếu được cung cấp.

8. TẦNG TRÌNH BÀY - CONTROLLER

File Mô tả
presentation/controllers/orders.controller.ts ORDERS CONTROLLER - Các route: POST / (tạo order), GET /:id (trạng thái), POST /:id/cancel (hủy), POST /:id/escrow/hold (admin), POST /:id/escrow/release (admin). Xác thực: JwtAuthGuard, RolesGuard cho các thao tác admin. Chuyển đổi DTO thành command.
presentation/controllers/payments.controller.ts PAYMENTS CONTROLLER - Các route: POST / (tạo thanh toán), POST /callback/:provider (webhook - Throttle + EndpointRateLimit), GET /:id (trạng thái), GET (danh sách), POST /:id/refund (admin hoàn tiền). QUAN TRỌNG: Endpoint callback có giới hạn tốc độ (Throttle + EndpointRateLimitGuard) - ngăn chặn lũ lụt callback.

9. TẦNG TRÌNH BÀY - DTO

File Mô tả
presentation/dto/create-order.dto.ts DTO: sellerId, listingId, amountVND (string), idempotencyKey (tùy chọn).
presentation/dto/cancel-order.dto.ts DTO: reason (string).
presentation/dto/create-payment.dto.ts DTO: provider (enum), type (enum), amountVND (string), description, returnUrl, transactionId (tùy chọn), idempotencyKey (tùy chọn).
presentation/dto/refund-payment.dto.ts DTO: reason (string).
presentation/dto/list-transactions.dto.ts DTO: status (tùy chọn), limit, offset.

10. MODULE & CÁC FILE KIỂM THỬ

File Mô tả
payments.module.ts CÀI ĐẶT MODULE - Đăng ký các repository, service, handler, controller.
index.ts (cấp module) Xuất API công khai.
infrastructure/repositories/index.ts Xuất các triển khai repository.
infrastructure/services/index.ts Xuất các dịch vụ gateway.
application/index.ts Xuất các handler command/query.
domain/repositories/index.ts Xuất các giao diện repository.
domain/entities/index.ts Xuất các thực thể.
domain/value-objects/index.ts Xuất các VO.
domain/events/index.ts Xuất các sự kiện domain.
presentation/controllers/index.ts Xuất các controller.
presentation/dto/index.ts Xuất các DTO.

Các File Kiểm Thử

File Mô tả
domain/__tests__/order.entity.spec.ts Kiểm thử đơn vị thực thể Order - máy trạng thái, các chuyển trạng thái
domain/__tests__/escrow.entity.spec.ts Kiểm thử đơn vị thực thể Escrow - hold, release, dispute, refund
domain/__tests__/payment.entity.spec.ts Kiểm thử đơn vị thực thể Payment
domain/__tests__/money.vo.spec.ts Kiểm thử xác thực Money VO
domain/__tests__/platform-fee.vo.spec.ts Kiểm thử tính toán phí nền tảng
domain/__tests__/payment-events.spec.ts Kiểm thử phát sự kiện domain
application/__tests__/create-order.handler.spec.ts Kiểm thử handler tạo order
application/__tests__/create-payment.handler.spec.ts Kiểm thử handler tạo thanh toán
application/__tests__/handle-callback.handler.spec.ts Kiểm thử xử lý callback
application/__tests__/handle-callback-edge-cases.handler.spec.ts Kiểm thử các trường hợp biên callback (race condition, idempotency)
application/__tests__/get-payment-status.handler.spec.ts Kiểm thử query trạng thái thanh toán
application/__tests__/refund-payment.handler.spec.ts Kiểm thử lệnh hoàn tiền
application/__tests__/list-transactions.handler.spec.ts Kiểm thử query danh sách giao dịch
infrastructure/__tests__/vnpay.service.spec.ts Kiểm thử gateway VNPay - xác minh chữ ký
infrastructure/__tests__/momo.service.spec.ts Kiểm thử gateway MoMo - xác minh HMAC-SHA256
infrastructure/__tests__/zalopay.service.spec.ts Kiểm thử gateway ZaloPay - phân tích JSON + xác minh MAC
infrastructure/__tests__/payment-gateway.factory.spec.ts Kiểm thử mẫu factory

TÓM TẮT KẾT QUẢ BẢO MẬT

CÁC BIỆN PHÁP BẢO MẬT MẠNH

  1. Xác Minh Chữ Ký Callback: Cả 3 nhà cung cấp (VNPay, MoMo, ZaloPay) đều xác minh chữ ký HMAC sử dụng crypto.timingSafeEqual() để so sánh thời gian cố định
  2. Ngăn Chặn Race Condition Nguyên Tử: paymentRepo.updateIfStatus() sử dụng mệnh đề WHERE có điều kiện để cập nhật nguyên tử chỉ khi ở trạng thái PENDING/PROCESSING
  3. Bảo Vệ Idempotency: Order + Payment kiểm tra idempotencyKey để ngăn chặn các thao tác trùng lặp
  4. Giới Hạn Tốc Độ: Endpoint callback có decorator Throttle + EndpointRateLimit
  5. Phân Quyền: Tất cả endpoint yêu cầu JwtAuthGuard; các thao tác admin yêu cầu RolesGuard
  6. Xác Thực Số Tiền: Money VO xác thực: 0 < amount ≤ 999_999_999_999 VND
  7. Xác Thực Máy Trạng Thái: Order + Escrow thực thi các chuyển trạng thái hợp lệ

⚠️ VẤN ĐỀ BẢO MẬT (CẦN KIỂM TRA)

  1. Race Condition Hold/Release Escrow: Không có Redis lock trên các handler hold-escrow/release-escrow - các yêu cầu đồng thời có thể gây ra sự không nhất quán trạng thái
  2. Không Có Cơ Chế Khóa Phân Tán: Các thao tác escrow không được bảo vệ trước các yêu cầu đồng thời từ các máy chủ khác nhau
  3. Idempotency Xử Lý Callback: Mặc dù paymentRepo.updateIfStatus() ngăn xử lý hai lần, kiểm tra idempotency không xác minh tính nhất quán của chữ ký callback
  4. Bí Mật Nhà Cung Cấp Thanh Toán: Các khóa được tải từ ConfigService - xác minh mã hóa biến môi trường khi lưu trữ
  5. Phân Quyền Hoàn Tiền: Chỉ kiểm tra vai trò ADMIN - không có xác thực logic nghiệp vụ (ví dụ: thời hạn hoàn tiền, số tiền hoàn tiền tối đa)
  6. Race Update Order/Escrow: Mặc dù hold là nguyên tử đối với thanh toán, cập nhật order + escrow trong handler được thực hiện tuần tự (2 lần gọi DB), không nguyên tử

CÁC FILE KHÔNG TÌM THẤY / NGOÀI PHẠM VI

  • Sử Dụng Redis Lock: Không tìm thấy Redis lock trong module thanh toán. MỐI LO NGẠI: Quan trọng cho escrow hold/release.
  • Tiện Ích Thanh Toán Dùng Chung: Không có module tiện ích thanh toán bên ngoài nào được tham chiếu
  • Mã Hóa Dữ Liệu Thanh Toán: Không có mã hóa cấp trường cho dữ liệu thanh toán nhạy cảm (mặc dù dịch vụ field-encryption tồn tại trong module shared)