# 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 | ✅ CÓ | 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 | ✅ CÓ | 100% | | Ủy quyền trên tất cả endpoint | ✅ CÓ | 100% | | Xác thực số tiền (min/max) | ✅ CÓ | 100% | | Giới hạn tốc độ trên callback | ✅ CÓ | 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 | ✅ CÓ | 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) 4. [ ] **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 5. [ ] **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 6. [ ] **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) 7. [ ] **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 8. [ ] **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Ó 9. [ ] **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 10. [ ] **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