Encrypt Payload
Phạm vi hệ thống
response payload encryptionlà yêu cầu hệ thống, không phải feature.- Thuật toán: AES-256-GCM (đối xứng), mã hoá body JSON của response.
- Đây là lớp obfuscation / chống scraping phía client, là lớp BỔ SUNG trên HTTPS/TLS — KHÔNG thay thế TLS.
- Server mã hoá response → browser tự giải mã bằng Web Crypto API.
Quy tắc một chiều
- Chỉ mã hoá RESPONSE. Request từ client vẫn gửi plaintext (được bảo vệ bởi TLS).
- Không có bước giải mã request phía server.
- Mục tiêu là làm khó việc scrape/đọc body tự động, không phải bảo mật transport (đã do TLS đảm nhận).
Bật/tắt & cấu hình
Namespace cấu hình: app.security.response-encryption.*.
| Thuộc tính | Ý nghĩa | Mặc định | Env |
|---|---|---|---|
enabled | Bật/tắt mã hoá response | false | RESPONSE_ENCRYPTION_ENABLED |
key | Secret base64 của đúng 32 byte (AES-256) | rỗng | RESPONSE_ENCRYPTION_KEY |
version | Version scheme ghi vào envelope | 1 | — |
include-paths | Whitelist Ant-pattern; rỗng = không mã hoá gì | rỗng | RESPONSE_ENCRYPTION_INCLUDE_PATHS |
Validate key lúc khởi động (fail-fast)
- Khi
enabled=true,keyđược validate ngay khi khởi động: phải là base64 hợp lệ và decode ra đúng 32 byte. - Nếu key rỗng / sai base64 / không đúng 32 byte → app KHÔNG khởi động (fail-fast).
- Khi
enabled=false,keyđược phép để trống để dev/test boot mà không cần key thật.
Không lưu key thật, secret hay nội dung
.envtrong tài liệu này. Key chỉ được nạp qua biến môi trường ở môi trường thật.
Version scheme
version(mặc định1) được ghi vào trườngvcủa envelope.- Mục đích: hỗ trợ xoay key / đổi thuật toán trong tương lai mà không đổi cấu trúc response — client đọc
vđể chọn đúng cách giải mã.
Môi trường
| Môi trường | Trạng thái |
|---|---|
prod | bật theo cấu hình (cần key 32 byte hợp lệ) |
dev | mặc định tắt |
test | tắt (app.security.response-encryption.enabled=false) |
Cơ chế whitelist (opt-in)
- Whitelist là Ant-pattern, so khớp trên request path đã strip context-path.
- Cơ chế là opt-in: chỉ path khớp ÍT NHẤT một pattern mới được mã hoá.
- Rỗng = không mã hoá gì — đây là default an toàn ở dev/test.
- Cấu hình động qua env
RESPONSE_ENCRYPTION_INCLUDE_PATHS(danh sách phân tách bằng dấu phẩy) → mở rộng/thu hẹp theo môi trường mà không đổi code.
Danh sách pattern mặc định
| Pattern | Nhóm endpoint | Ghi chú |
|---|---|---|
/listings/** | Listing (tin đăng) | Toàn bộ API tin đăng |
/marketplace/listings/** | Listing trên marketplace | Listing trong khu vực marketplace |
/properties/** | Bất động sản / property | Dữ liệu property |
/users/** | Người dùng | Hồ sơ, thông tin user |
/auth/** | Xác thực | Login, register, OTP, token… |
/contacts/** | Danh bạ liên hệ | Contact / liên hệ |
/wallet/** | Ví / số dư | Số dư, giao dịch ví |
/payments/** | Thanh toán | Luồng thanh toán |
/v1/payments/** | Thanh toán (v1) | Endpoint thanh toán versioned |
/subscriptions/me/** | Gói thuê bao của user hiện tại | Subscription của chính user |
/favorites/** | Yêu thích | Danh sách favorite |
/notifications/** | Thông báo | Notification của user |
/ai/** | Tính năng AI | Các API AI |
/admin/** | Khu vực admin | API quản trị |
/uploads/** | Upload | Luồng upload |
Envelope contract
Khi một response đủ điều kiện mã hoá, body JSON gốc được thay thế bằng envelope:
{ "v": 1, "iv": "<base64 IV 12 byte>", "data": "<base64 ciphertext + GCM tag 128-bit>"}| Trường | Ý nghĩa |
|---|---|
v | Version scheme (lấy từ cấu hình version) — client dùng để chọn đúng cách giải mã |
iv | IV ngẫu nhiên 12 byte, sinh mới mỗi response, không bao giờ tái dùng (yêu cầu nonce của GCM) |
data | Ciphertext + GCM auth tag 128-bit nối ở cuối — đúng layout Web Crypto AES-GCM của browser |
Header báo hiệu cho client
| Header | Giá trị | Mục đích |
|---|---|---|
X-Encrypted | true | Báo client đi nhánh giải mã |
Content-Type | application/json | Giữ nguyên kiểu nội dung |
Content-Length | (bị bỏ) | Loại bỏ vì kích thước body thay đổi sau mã hoá |
Điểm áp dụng & thứ tự
- Mã hoá áp dụng ở tầng response advice, chạy SAU lớp wrap + i18n của
ApiResponse.- Thứ tự: response wrap/i18n advice = order 0, encryption advice = order 100.
- Hệ quả: toàn bộ envelope
ApiResponseđược mã hoá, không chỉ phầndatabên trong.
- Cipher chỉ tồn tại khi
enabled=true. Khi tắt, lớp advice trơ (inert) → mọi response đi plaintext.
Trường hợp LOẠI TRỪ (không mã hoá)
- Body
nullhoặc HTTP204 No Content. - Body nhị phân / streaming (
byte[],Resource,StreamingResponseBody). - Handler tài liệu Swagger/OpenAPI (package
org.springdoc,springfox). - Mọi path KHÔNG khớp whitelist
include-paths.