ADR-0003. Mã hoá AES-256-GCM cho credential nhà cung cấp khi lưu trữ
| Trường | Giá trị |
|---|---|
| Trạng thái | Accepted |
| Ngày | 2026-02-12 |
| Người quyết định | Phat Nguyen |
| Thay thế | - |
Bối cảnh
- Credential của nhà cung cấp thanh toán (VNPAY appId/secret, token theo từng merchant) cực kỳ nhạy cảm - rò rỉ là có thể thanh toán trái phép.
- Lưu chúng dưới dạng văn bản thuần trong bảng
Configurationlà điều không chấp nhận được. - Chúng tôi cần cân bằng giữa bảo mật và sự đơn giản trong vận hành (quy mô hiện tại chưa đòi hỏi HSM/KMS).
Quyết định
Toàn bộ credential thanh toán được mã hoá khi lưu trữ bằng AES-256-GCM thông qua CryptoUtility (từ @nx/core). Khoá mã hoá được dẫn xuất từ APP_ENV_APPLICATION_SECRET.
Cụ thể:
- Cột
Configuration.credentialđược ẩn khỏi các thao tác đọc CRUD chuẩn (trường ẩn của drizzle). PaymentConfigurationService.getPaymentCredentialtruy cập cột trực tiếp qua drizzle connector và giải mã ngay tại chỗ.- Cùng một secret đó mã hoá các cấu hình payment không phải credential trong
tValue(ví dụmasterMerchantCode,appIdcủa VNPAY). - Tất cả pod (API + WORKER) BẮT BUỘC dùng chung
APP_ENV_APPLICATION_SECRET.
Hệ quả
| Ưu điểm | Nhược điểm |
|---|---|
| Chỉ riêng bản dump database không làm lộ credential | Mô hình một secret - lộ secret = mất an toàn toàn bộ |
| Mã hoá có xác thực (chế độ GCM) ngăn giả mạo | Xoay vòng secret đòi hỏi mã hoá lại mọi hàng credential (thủ công) |
| Giải mã trong cùng tiến trình - dưới một mili giây | Không cô lập KMS theo từng merchant |
| Primitive tiêu chuẩn, đã được kiểm định kỹ | App secret phải lưu trong K8s secret với RBAC nghiêm ngặt |
Quy trình xoay vòng
- Sinh secret mới.
- Đọc tất cả hàng
Configurationcó credential, giải mã bằng secret cũ. - Mã hoá lại bằng secret mới.
- Triển khai lại với env mới.
Việc xoay vòng BẮT BUỘC phải được điều phối - không để xảy ra trạng thái triển khai dở dang nơi các pod dùng secret khác nhau.
Phương án đã cân nhắc
| Lựa chọn | Ưu điểm | Nhược điểm | Lý do từ chối |
|---|---|---|---|
| HashiCorp Vault / AWS KMS | Khoá riêng từng credential, có sẵn cơ chế xoay vòng | Phụ thuộc nhà cung cấp, tốn chi phí vận hành, thêm độ trễ | Quá sớm so với quy mô của chúng tôi |
| Bất đối xứng (RSA theo từng merchant) | Cô lập theo merchant | Phức tạp; bùng nổ số lượng khoá | Không cần thiết với mô hình mối đe doạ hiện tại |
| Văn bản thuần + DB ACL | Đơn giản | Không chấp nhận được - bộ phận vận hành DB đọc được credential | Không |
Tham chiếu
core/src/utilities/crypto.utility.ts(CryptoUtility)services/payment-configuration.service.ts:43-176(các điểm giải mã)core/src/models/schemas/public/configuration/schema.ts(cộtcredentialẩn)