# SEC — Security Architecture & Threat Model — e-commerce | | | |---|---| | **Version** | 1.1 | | **Date** | 2026-09-15 | | **Author** | SA (skill sa-2-architecture, chế độ `go`, hoạt động `sec`) | | **Status** | 🟡 Draft *(duyệt từng phần — xem `Approved by`; AG2 cần cả ba vai trò Tech Lead/Security/Ops-SRE ký, mới có một chữ ký thay có điều kiện — **chưa đủ điều kiện chuyển `🔵 Approved`**)* | | **Approved by** | Tech Lead: **Điều phối dự án** (uỷ quyền, chế độ chạy thử — ký thay theo ngoại lệ `DEC-01`, **không phải chữ ký Tech Lead thật**) — duyệt **từng phần** bản v1.0 · 2026-09-15: ghi nhận nội dung 31 `THR` STRIDE (§4), map `ROLE-01/02` (§3.1), mô hình authn/authz đề xuất (§2, §3), SAQ A (§8.1), đề xuất rate limit **30/10/10 req/phút** (§5.3, `ASM-40`), quản lý secret/scanning (§6), audit log theo phương án (a) (§7). Chốt **TẠM** hướng `OQ-050`: chọn **PA-3** (service JWT ngắn hạn ký bởi Identity & Access) cho service-to-service authn (§2.4) — yêu cầu SA viết `ADR-015` (`Proposed`) ở lượt hoạt động `adr` kế tiếp, cùng lúc với `ADR-014` (Outbox) đang nợ; `OQ-050` **giữ nguyên mở**, chờ Security + Ops/SRE thật xác nhận trước khi `Accepted`. **KHÔNG ký thay Security** — mọi kết luận PII/residency/retention (§5, §8.2) vẫn là **đề xuất chờ Legal/Security**, chưa có hiệu lực. Ghi thêm `DEC-28`. Security: **—** *(chưa có người được chỉ định — `OQ-007`, mở từ GĐ1. SEC **CHƯA CÓ HIỆU LỰC PHỦ QUYỀN AG2** cho tới khi có người này; không ký thay ở lượt này)* · Ops/SRE: **—** *(chưa ký)*. `OQ-004` (tính hợp lệ ký thay) vẫn mở. `Confidence` **giữ nguyên** 🔴 — duyệt từng phần không phải bằng chứng nguồn mới. Status **giữ** 🟡 Draft — AG2 chưa đủ ba chữ ký thật/hợp lệ. | | **Source** | `02-architecture/SAD_e-commerce_v1.0.md` v1.3 §3, §4, §4.1, §7 · `02-architecture/DAT_e-commerce_v1.0.md` v1.0 §1, §5, §5.1, §5.2, §6, §9 · `02-architecture/ICD_e-commerce_v1.0.md` v1.0 §1, §2, §3.1–§3.7 · `02-architecture/FAIL_e-commerce_v1.0.md` v1.1 §1, §5 (`FM-06` ownership fail-closed, `E-CART-0007`) · `02-architecture/QAS_e-commerce_v1.0.md` `QAS-010/011/012` · `02-architecture/ASR_e-commerce_v1.0.md` `ASR-002/004/007/008/009` · `02-architecture/adr/ADR-002_*.md`, `ADR-004_*.md`, `ADR-007_*.md`, `ADR-008_*.md`, `ADR-009_*.md`, `ADR-011_*.md`, `ADR-015_*.md` · `01-context/CTX_e-commerce_v1.0.md` §4.2 (đối tác ngoài) · `01-context/ARISK_e-commerce_v1.0.md` §3 (`ARISK-03/04/06`) · `00-index/OQ_e-commerce.md` v1.21 · `00-index/DEC_e-commerce.md` v1.24 · `ba-output/e-commerce/02-analysis/RBAC_CartCheckout_v1.0.md` §1, §2, §4, §5, §6, §8 · `ba-output/e-commerce/03-specification/NFR_US002-003_v1.0.md` §3 · `e-commerce/docs/sections/08-bao-mat.md` *(P1, chỉ tham khảo — xem cảnh báo §0.2, KHÔNG kế thừa kiến trúc ~10 microservices/Kafka của tài liệu đó)* | | **Scope** | Toàn sàn e-commerce theo P2 (`SAD` v1.3, 15 `CMP`). Chi tiết nhất: **Cart & Order** (`CMP-04`), **Payment** (`CMP-11`/`CMP-14`), **Identity & Access** (`CMP-02`), và luồng chia sẻ PII cho seller khi tách đơn (`ADR-008`, `DAT §5`). Các `CMP` còn lại (Seller Mgmt, Commission, Promotion, Review, Notification, Shipping) ở mức ranh giới tin cậy + authz tổng quát, không đào sâu threat model riêng — đây là hoạt động 6/9 (`sec`) của `sa-2-architecture`. | | **Confidence** | 🔴 Giả định chưa xác minh — theo yêu cầu điều phối, tiếp nối `Confidence` 🔴 của `SAD`/`ICD`/`DAT`/`FAIL`/`ASR`/`QAS`. AG1 chưa ký thật; AG2 chưa tới hạn; `ADR-002/004/007/008/009/011` đều `Proposed` (chưa `Accepted`); `ADR-008` (PII) **chặn hoàn toàn** vì chưa có đại diện Pháp chế/Bảo mật (`OQ-007`); không đối tác ngoài nào (VNPay/Momo/GHN/GHTK) có sandbox/tài liệu API thật (`ARISK-03/04`) để xác minh cơ chế chữ ký webhook thật. Mọi ngưỡng rate-limit/circuit/authn trong tài liệu này là **đề xuất SA**, chưa Security/Tech Lead xác nhận. | ## Change Log | Version | Date | Người sửa | Thay đổi | ADR/DEC | |---|---|---|---|---| | 1.0 | 2026-09-15 | SA (qua skill sa-2-architecture, chế độ `go`, hoạt động `sec`) | Bản đầu — hoạt động 6/9 của GĐ2. Threat model STRIDE cho 8 ranh giới tin cậy (client↔ALB/WAF, ALB↔Nhóm Giao dịch, Nhóm Giao dịch↔Nhóm Hỗ trợ cross-network `IF-021/022`, Cart&Order↔Payment `IF-006`, Payment↔VNPay/Momo + webhook inbound, Shipping↔GHN/GHTK webhook, app↔RDS/Redis/SQS, Admin console) — 28 `THR-01…28`, mỗi cái truy về `QAS`/`ASR`/`ADR` nguồn. Mô hình authn cho Guest/Customer/Seller/Admin + đề xuất mới cho service-to-service (Nhóm Giao dịch↔Nhóm Hỗ trợ↔Payment — chưa có cơ chế, radar ước lượng ~6, `ADR` ứng viên chưa viết). Mô hình authz: map đủ `ROLE-01/02` của `RBAC_CartCheckout` xuống quyền kỹ thuật, fail-closed cho ownership check (`E-CART-0007`, theo `FAIL`). Phân loại PII/mã hoá/masking/residency — toàn bộ đánh dấu "đề xuất chờ Legal/Security" (`OQ-007`). PCI-DSS SAQ A: xác nhận ranh giới `ADR-002`, đề xuất bắt buộc tích hợp dạng redirect (chưa xác nhận với đối tác thật — `OQ-048` mới); webhook: cơ chế chữ ký thật chưa biết (chưa bịa — `OQ-049` mới, `ARISK-03/04`), chống replay theo `ADR-004`. Đề xuất số cụ thể cho rate limit Guest cart (`OQ-023`), login brute-force (`OQ-052` mới), checkout. Quản lý secret (Secrets Manager, rotation), quét dependency/container (Trivy/Snyk), pentest năm + ASV quý (`OQ-017` đã mở ở `TCO`). Audit log theo phương án (a) đã chốt TẠM ở `OQ-047` (mỗi module tự ghi) — chốt trường bắt buộc + retention. Đối chiếu `docs/sections/08-bao-mat.md` chỉ tham khảo (P1, §0.2). Đề xuất `FIT-29…33` cho GĐ3 (authz test tự động, secret scan, service-authn test, webhook signature test, audit completeness test). Thêm `OQ-048…053`, cập nhật `OQ-007/023/024`, `ASM-39…41`. Ghi ngoại lệ tiếp tục gate ở `DEC-27` (`00-index/DEC_e-commerce.md`), tiếp nối `DEC-01…26`. Không sửa `SAD`/`ICD`/`DAT`/`FAIL`/`ADR` đã có. `Confidence` 🔴 toàn bộ. | `DEC-27` | | 1.0 | 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) — tác vụ **sign/approve** | Duyệt **từng phần**: ghi nhận nội dung 31 `THR` STRIDE (§4), map `ROLE-01/02` (§3.1), mô hình authn/authz đề xuất (§2, §3), SAQ A (§8.1), đề xuất rate limit **30/10/10 req/phút** (§5.3, `ASM-40`), quản lý secret/scanning (§6), audit log theo phương án (a) (§7). Chốt **TẠM** `OQ-050`: chọn **PA-3** (service JWT ngắn hạn) cho service-to-service authn (§2.4) — yêu cầu SA viết `ADR-015` (`Proposed`) ở lượt hoạt động `adr` kế tiếp cùng `ADR-014`; `OQ-050` giữ nguyên mở, chờ Security + Ops/SRE. **KHÔNG ký thay Security** — header `Approved by → Security` giữ `—`, `SEC` **chưa có hiệu lực phủ quyết AG2** (`OQ-007`); mọi kết luận PII/residency/retention (§5, §8.2) vẫn là đề xuất chờ Legal/Security, không phải quyết định cuối. Không đổi nội dung chuyên môn nào của tài liệu. Ops/SRE chưa ký; `Confidence` giữ 🔴; Status giữ 🟡 Draft; AG2 chưa ký. Ghi thêm `DEC-28`. | `DEC-28` | | 1.1 | 2026-09-15 | SA (qua skill sa-2-architecture, chế độ `go`, hoạt động `adr`) | **Chỉ link ADR, không đổi nội dung.** `ADR-015` (Service JWT ngắn hạn service-to-service, `Proposed`) vừa được viết theo hướng PA-3 đã chọn TẠM ở §2.4/`OQ-050`/`DEC-28` — thay các dòng "chưa viết `ADR`" ở §2.4 và `THR-09`/`THR-13` (§4.3/§4.4) bằng đường dẫn `adr/ADR-015_service-jwt-xac-thuc-service-to-service.md`. `OQ-050` giữ nguyên mở (chặn cứng bởi `OQ-007` — Security chưa có người, xem `ADR-015 §0`/§3). Không sửa nội dung chuyên môn nào khác của `SEC`. Ghi `DEC-31` (tiếp nối `DEC-01…30`). | `ADR-015`, `DEC-31` | > Sơ đồ thắng về **quan hệ và luồng** (ai gọi ai, qua ranh giới nào). > Bảng/văn bản thắng về **ràng buộc và con số** (ngưỡng rate-limit, TTL token, mức che dữ liệu). > Mâu thuẫn ngoài hai loại trên là lỗi tài liệu, phải sửa chứ không chọn bên (`D12`). --- ## 0. Ghi chú Preflight & phạm vi — bắt buộc đọc trước ### 0.1 Ngoại lệ gate **AG1 vẫn chưa ký thật; AG2 (gate của chính GĐ2) chưa tới hạn.** Theo `SKILL.md`, hoạt động 1 (`QAS`) → 2 (`ASR`) → 3 (`SAD`) đã hoàn tất và được duyệt từng phần (`DEC-12/14/16`); hoạt động 4 (`ICD`), 5 (`DAT`), 8 (`FAIL`) đã chạy (`DEC-18…25`), `ADR-001…013` đã viết (tất cả `Proposed`). Điều kiện đầu vào cho hoạt động 6 (`SEC`) — `SAD`, `DAT`, `RBAC` của BA — đã đủ. Người dùng (vai điều phối dự án chạy thử) đã được cảnh báo lại và **khẳng định muốn tiếp tục**. > **DEC-27 (SA)** — Tiếp tục `sa-2-architecture` (hoạt động 6 — `SEC`) cho e-commerce trong khi > AG1 chưa ký thật và AG2 chưa tới hạn — tiếp nối `DEC-01…26`. > **Quyết định:** Dựng threat model STRIDE + mô hình authn/authz + phân loại PII cho toàn sàn P2 > dựa trên `SAD v1.3`/`DAT v1.0`/`ICD v1.0`/`FAIL v1.1`/`RBAC_CartCheckout` đã có, giữ > `Confidence 🔴` cho tới khi: (a) AG1/AG2 ký thật, (b) có đại diện Pháp chế/Bảo mật thật > (`OQ-007`) — **điều kiện chặn cứng nhất**, không có `SEC` nào có hiệu lực phủ quyết PII/residency > nếu thiếu người này, (c) đối tác VNPay/Momo/GHN/GHTK có tài liệu/sandbox thật để xác minh cơ chế > chữ ký webhook (`ARISK-03/04`), (d) Tech Lead xác nhận các đề xuất mới (service-to-service authn, > ngưỡng rate-limit, account lockout). > **Người quyết:** Điều phối dự án (đại diện PO, dự án chạy thử). > **Radar (ước lượng cho việc tiếp tục dưới ngoại lệ):** ~4 — chi phí đảo ngược thấp (ghi tài liệu > threat model, chưa có dòng code phụ thuộc) · bán kính ảnh hưởng: hoạt động `inf` kế tiếp và toàn > bộ dev dùng `SEC` làm nguồn sự thật authn/authz/PII, nhưng bản thân *việc ghi tài liệu dưới ngoại > lệ* thì nhỏ · có chạm `QAS-010/011/012` Must trực tiếp (đang thiết kế cách đạt chúng) nhưng chưa > phải cam kết thi công (chưa `FIT` nào chạy) · không ràng buộc dài hạn tự thân (văn bản `SEC` sửa > được qua version mới) · không tranh cãi mới, tiếp nối tiền lệ `DEC-11…26` → **ghi `DEC-nn`, > không cần `ADR` cho việc chạy dưới ngoại lệ** (`decision-radar.md §1–§2`). > **Hệ quả nếu không chấp nhận ngoại lệ:** hoạt động `inf` (hoạt động 7) không có mô hình threat/ > authn/authz để thiết kế network segmentation và secret management thật — chậm tiến độ chạy thử > tương ứng thời gian xử lý các `OQ` đang mở, đặc biệt `OQ-007` (chặn `ADR-008` và phần lớn §5). ### 0.2 Đối chiếu `docs/sections/08-bao-mat.md` — chỉ tham khảo, không kế thừa `docs/sections/08-bao-mat.md` (P1, `status: approved`, `version: 2`) là thiết kế bảo mật cho kiến trúc **~10 microservices + Kafka/MSK + database-per-service** — kiến trúc đó **đã bị loại** ở `OPT §5` (GĐ1), thay bằng P2 (modular monolith + managed AWS, Payment tách riêng). Tài liệu này **chỉ tái dùng**: (a) quy ước đặt tên mã lỗi (`403 ERR_FORBIDDEN_OWNERSHIP`, `423 ERR_ACCOUNT_LOCKED`), (b) ý tưởng chính sách khoá tài khoản theo vai trò (§8.1.1a), (c) ý tưởng redact PII trong audit log (§8.2.5a), (d) danh mục OWASP Top 10 rà theo endpoint — **không kế thừa** cấu trúc scope `customer:*`/`seller:*`/`admin:*` gắn với 10 service riêng, không kế thừa giả định Kafka/MSK ACL (P2 dùng SQS FIFO/EventBridge, đã có ở `ADR-005`), không kế thừa bảng `audit_log` tập trung một Service Audit & Compliance (P2 chọn phương án (a) — mỗi module tự ghi, `OQ-047`). Mọi chỗ tái dùng được đánh dấu rõ "tham khảo P1" trong bảng tương ứng bên dưới. 🔴 **Nhắc quan trọng:** `INF` (hoạt động 7) **chưa được tạo**. Tài liệu này là input trực tiếp cho `INF` — đặc biệt network segmentation (§1), secret management (§6), và ngưỡng alerting an ninh. --- ## 1. Ranh giới tin cậy *8 ranh giới theo yêu cầu người duyệt. Mỗi ranh giới phải có kiểm tra đầu vào tại đúng điểm giao.* ```mermaid flowchart LR subgraph NET["Internet — không tin cậy"] U["Guest/Customer/Seller/Admin"] VNP["VNPay"] MOMO["Momo"] GHN["GHN"] GHTK["GHTK"] end subgraph EDGE["Vùng biên — TB1"] WAF["WAF + ALB (CMP-01)"] end subgraph GD["Nhóm Giao dịch — TB2 (tin cậy vừa)"] ID["Identity & Access (CMP-02)"] CAT["Catalog & Inventory (CMP-03)"] CO["Cart & Order (CMP-04)"] end subgraph HT["Nhóm Hỗ trợ — tin cậy vừa (khác network TB2)"] PROMO["Promotion & Loyalty (CMP-07)"] SELLER["Seller Mgmt (CMP-05)"] SHIP["Shipping & Fulfillment (CMP-10)"] end subgraph PAY["Payment Service — TB4 (cô lập PCI, tin cậy cao nhất nội bộ)"] PS["Payment (CMP-11)"] end subgraph DATA["Vùng dữ liệu — TB5"] RDS[("RDS chính")] RDSPAY[("RDS Payment")] REDIS[("Redis")] SQS[("SQS/EventBridge")] end subgraph ADMIN["Admin console — TB6"] ADM["Admin Backoffice"] end U -->|"TB1 · HTTPS, WAF+TLS termination"| WAF WAF -->|"TB2 · HTTPS, authn JWT/Guest"| ID WAF -->|"TB2"| CAT WAF -->|"TB2"| CO WAF -->|"TB4 · HTTPS, cô lập mạng"| PS ADM -->|"TB6 · HTTPS, MFA + IP allowlist (đề xuất)"| ID CO -->|"TB3 · REST cross-network, chưa có service-authn"| PROMO CO -->|"TB3 · REST cross-network"| SELLER CO -->|"TB4 · REST, chưa có service-authn"| PS PS -->|"TB-ext · REST sync + webhook async"| VNP PS -->|"TB-ext"| MOMO SHIP -->|"TB-ext · REST sync + webhook async"| GHN SHIP -->|"TB-ext"| GHTK ID -->|"TB5 · TLS, IAM theo schema"| RDS CO -->|"TB5"| RDS CO -->|"TB5"| REDIS CO -->|"TB5 · publish"| SQS PS -->|"TB5 · TLS, IAM riêng biệt"| RDSPAY SQS -->|"TB5 · consume"| HT ``` **Legend:** ▭ vùng tin cậy khác nhau bằng subgraph · mũi tên ghi giao thức + loại kiểm tra tại ranh giới đó · `TBn` tham chiếu đúng số ranh giới ở bảng dưới. | # | Ranh giới | Từ vùng | Sang vùng | Kiểm tra gì tại đây | `CMP` chịu trách nhiệm | |---|---|---|---|---|---| | TB1 | Client → ALB/WAF | Internet (không tin cậy) | Biên hệ thống | TLS 1.2+ termination, WAF (OWASP Core Rule Set), rate-limit L7, giới hạn kích thước payload, chặn IP theo reputation (đề xuất) | `CMP-01` | | TB2 | ALB → Nhóm Giao dịch | Biên | Nội bộ tin cậy vừa | Authn hợp lệ (JWT Customer / `X-Guest-Session-Id` Guest) — **KHÔNG** authz chi tiết theo dữ liệu (đúng `SAD §4.1` "cái `CMP-01` KHÔNG làm") | `CMP-01` → `CMP-02/03/04` | | TB3 | Nhóm Giao dịch ↔ Nhóm Hỗ trợ (`IF-021`/`IF-022`) | Nội bộ tin cậy vừa | Nội bộ tin cậy vừa (network khác — 2 ECS Fargate service riêng, `OQ-026`) | 🔴 **Chưa có cơ chế xác thực service-to-service** — hiện chỉ có network reachability (security group nội bộ VPC), chưa xác thực danh tính bên gọi. Xem §2.5, `THR-09…12` | `CMP-04` ↔ `CMP-07`/`CMP-05` | | TB4 | Cart & Order → Payment (`IF-006`) | Nội bộ tin cậy vừa | Vùng cô lập PCI cao nhất | Tương tự TB3 — chưa có service-authn; **đây là ranh giới nhạy cảm nhất** vì Payment giữ tiền thật (`ASR-002`) | `CMP-04` → `CMP-11` | | TB5 | Payment ↔ VNPay/Momo (init sync + webhook inbound async) | Vùng cô lập PCI | Internet (đối tác bên thứ ba) | Chữ ký/HMAC theo tài liệu đối tác (🔴 chưa có, `ARISK-03`), chống replay (`ADR-004`, lệch ≤5 phút), TLS | `CMP-11` | | TB6 | Shipping & Fulfillment ↔ GHN/GHTK webhook | Nhóm Hỗ trợ | Internet (đối tác) | Chữ ký/token theo tài liệu đối tác (🔴 chưa có, `ARISK-04`), không ghi đè trạng thái thụt lùi (`FAIL FM-03/04`) | `CMP-10` | | TB7 | App (mọi `CMP`) ↔ RDS/Redis/SQS | Nội bộ tin cậy vừa/cao | Vùng dữ liệu | TLS in-transit, IAM/network ACL theo schema-per-module (`ADR-006`) — **không module nào được truy cập schema của module khác**, RDS Payment tách hoàn toàn (`ADR-002`) | mọi `CMP` ứng dụng → `CMP-13/14/15/12` | | TB8 | Admin console → Identity & Access + toàn hệ thống | Internet (giới hạn, đề xuất VPN/IP allowlist) | Nội bộ tin cậy cao | MFA bắt buộc (`ASR-009`), IP allowlist/VPN (đề xuất — tham khảo P1 §3.3, chưa quyết định hạ tầng cho P2, `OQ-050`), audit toàn bộ hành động | `CMP-02` (phần Admin) | 🔴 **TB3 và TB4 là phát hiện mới của hoạt động `sec`** — `SAD`/`ICD`/`FAIL` đã ghi nhận đây là cross-network call (`OQ-026/028`) nhưng **chưa từng thiết kế cơ chế xác thực danh tính bên gọi**, chỉ có network reachability. Một service nào đó trong cùng VPC (kể cả bị compromise) có thể gọi thẳng `IF-006`/`IF-021`/`IF-022` nếu không có kiểm soát bổ sung. Xem §2.5 (đề xuất) và `THR-09/13`. --- ## 2. Xác thực (Authentication) | | Quyết định | `ADR`/Nguồn | |---|---|---| | **Cơ chế (Customer)** | Bearer JWT | `ICD §1` mục 9 — kế thừa `04-api-design.md §4.2`, chưa có `ADR` riêng | | **Cơ chế (Guest)** | Header `X-Guest-Session-Id` (giá trị CSPRNG ≥128-bit) + cookie `HttpOnly; Secure; SameSite=Lax` | `ICD §1` mục 10 | | **Cơ chế (Seller/Admin)** | Bearer JWT (kế thừa cùng cơ chế Customer, khác `role` claim) | Suy từ `CMP-02`, chưa có tài liệu riêng ngoài phạm vi US-002/003 | | **Nơi giữ trạng thái** | Stateless (JWT) cho Customer/Seller/Admin · **Stateful** cho Guest (session lưu ở Redis, `CMP-15`, theo `DAT §1.1`) | `DAT §1.1` | | **Thời hạn access token** | 🔴 **Chưa chốt số cụ thể cho P2** — `ICD §1` mục 9 chỉ ghi "~15-60 phút (kế thừa `04-api-design.md §4.2`)"; đây là khoảng tham khảo P1, chưa xác nhận cho P2. Đề xuất SA: **15 phút** (an toàn hơn, giảm cửa sổ lợi dụng token bị đánh cắp) — xem `OQ-051` | — | | **Refresh token** | 🔴 Chưa chốt — đề xuất SA: có, TTL 14 ngày, **không** áp dụng rotation phức tạp kiểu P1 (`docs/08 §8.1.1` refresh token rotation + reuse detection) ở MVP P2 vì tăng độ phức tạp mà chưa có bằng chứng cần thiết cho quy mô hiện tại; ghi nhận là điểm có thể nâng cấp khi có sự cố thật — xem `OQ-051` | Tham khảo P1, **không kế thừa nguyên trạng** | | **Cách thu hồi ngay lập tức** | 🔴 **Chưa có cơ chế** — JWT stateless không có denylist. Đề xuất SA: denylist Redis theo `jti`, TTL = thời hạn còn lại của token, tra cứu tại middleware authn mỗi request (thêm ~1 Redis lookup, chấp nhận được vì Redis đã là phụ thuộc sẵn có, `CMP-15`) — áp dụng khi: đổi mật khẩu, Admin khoá tài khoản, logout (tuỳ chọn). **Chưa Tech Lead xác nhận** | `OQ-051` (mới) | | **Đa yếu tố (MFA)** | Bắt buộc cho Admin, khuyến khích (không bắt buộc) cho Seller (`ASR-009`, `QAS-012`). Phương thức: **TOTP app (RFC 6238)** — chốt TẠM theo `OQ-024`/`DEC-14`/`ASM-20`, **chưa Security thật xác nhận**, `OQ-024` vẫn mở | `ASR-009` | | **Backup code khi mất thiết bị MFA** | 🔴 Chưa thiết kế — đề xuất 10 mã dùng một lần khi enroll (tham khảo P1 §8.1.1, không sao chép nguyên bản vì P1 gắn với endpoint `/v1/auth/mfa/enroll` cụ thể chưa xác nhận tồn tại ở P2) | `OQ-024` | | **Nơi ký/xác minh chữ ký JWT** | Identity & Access (`CMP-02`) ký bằng khoá riêng; các `CMP` khác **chỉ xác minh** (không tự ký) | `CMP-02` | | **Xoay khoá ký JWT** | 🔴 Chưa chốt tần suất — đề xuất tham khảo chung ngành: 90 ngày, dùng `kid` trong header JWT để hỗ trợ 2 khoá song song trong giai đoạn chuyển tiếp | `OQ-051` | ### 2.1 Guest session — chi tiết | | | |---|---| | TTL | 30 ngày không hoạt động (`ICD §1` mục 10, `DAT §1.1`) | | Rotation | 🔴 **Không có** — cùng một `X-Guest-Session-Id` dùng suốt vòng đời phiên, không xoay định kỳ. Rủi ro: nếu giá trị bị lộ (session fixation qua log/URL), kẻ tấn công giữ quyền truy cập tới hết TTL. Đề xuất SA: xoay giá trị session tại thời điểm Guest chuyển đổi thành Customer (đăng ký/đăng nhập) — chưa thiết kế chi tiết, ghi `OQ-051` | | Nơi giữ | Redis (`CMP-15`), là **nguồn sự thật của session** (không có bản ghi RDS song song, `DAT §1.1`) | | Hết hạn | Guest mất phiên, phải tạo giỏ mới (`BR-CART §3`, đúng thiết kế) | ### 2.2 Customer JWT — chi tiết | | | |---|---| | Thuật toán | 🔴 Chưa chốt — đề xuất **RS256** (asymmetric, cho phép các `CMP` khác chỉ cần public key để verify, không cần chia sẻ secret) thay vì HS256 (symmetric, mọi service verify phải giữ cùng secret — rủi ro lan rộng nếu 1 service bị lộ secret) | | Claims tối thiểu | `sub` (customerId), `role`, `iat`, `exp`, `jti` (phục vụ denylist §2 trên) — **chưa chốt scope claim chi tiết**, xem §3 | | TTL access/refresh | Xem bảng §2 trên — cả hai **chưa chốt số cuối**, `OQ-051` | ### 2.3 Seller / Admin — chi tiết *Ngoài phạm vi chi tiết hoá của module Giỏ hàng & Checkout (`RBAC_CartCheckout §1` cố ý không đưa Seller/Admin vào ma trận) — SEC chỉ ghi nhận yêu cầu tối thiểu do `ASR-009` ép ra:* | | | |---|---| | Seller | JWT giống Customer, `role=seller`, MFA khuyến khích không bắt buộc | | Admin | JWT giống Customer, `role=platform_admin`, **MFA bắt buộc** (TOTP, `ASM-20`); đề xuất bổ sung giới hạn mạng (VPN/IP allowlist) — tham khảo P1 `docs/08 §3.3`, **chưa quyết định hạ tầng cho P2** vì `INF` (hoạt động 7) chưa chạy — ghi `OQ-050` | | Account lockout (brute-force) | 🔴 Chưa thiết kế cho P2 — đề xuất SA (tham khảo ý tưởng P1 `docs/08 §8.1.1a`, **số ngưỡng đề xuất lại cho P2**, chưa kế thừa nguyên bản): `customer`/`seller` 5 lần sai liên tiếp → khoá 15 phút; `platform_admin` 3 lần sai liên tiếp → khoá 30 phút (ngưỡng thấp hơn vì quyền hạn cao hơn). **Chưa Security/Tech Lead xác nhận** — `OQ-052` (mới) | ### 2.4 Service-to-service (Nhóm Giao dịch ↔ Nhóm Hỗ trợ ↔ Payment) 🔴 **Đây là khoảng trống kiến trúc phát hiện bởi hoạt động `sec`** — chưa `ADR` nào (`ADR-002`, `ADR-007`) quyết định cơ chế xác thực **giữa hai service nội bộ** (chỉ quyết định xác thực **người dùng cuối** tới service). `IF-006`/`IF-021`/`IF-022` hiện chỉ dựa vào network reachability (security group VPC) — không có gì ngăn một service khác trong cùng VPC giả danh gọi thẳng các endpoint này nếu security group bị cấu hình sai hoặc một service bị compromise. **Ba phương án đã cân nhắc** *(quy tắc `D3` — chưa viết `ADR` chính thức, đề xuất cho hoạt động `adr` kế tiếp)*: | Phương án | Mô tả | Ưu | Nhược | |---|---|---|---| | **PA-1 — Chỉ dựa network (security group)** | Giữ nguyên hiện trạng — không thêm gì | Không tốn công triển khai | Không đáp ứng "defense in depth" cho dữ liệu PII/tiền đi qua TB3/TB4; một security group cấu hình sai = không còn ranh giới nào | | **PA-2 — mTLS qua service mesh (AWS App Mesh/Private CA)** | Mỗi ECS task có chứng chỉ riêng, xác thực lẫn nhau ở tầng TLS | Mạnh nhất, chuẩn ngành cho zero-trust nội bộ | Thêm hạ tầng mới (App Mesh) — **`SAD §7` v1.2 đã ghi rõ "không tự thêm hạ tầng mới (VD internal ALB/App Mesh) vào sơ đồ vì đó là quyết định kiến trúc mới, ngoài phạm vi"** — mâu thuẫn trực tiếp với ghi chú đó nếu chọn ngay bây giờ; cần quyết định lại ở `inf`/`adr` | | **PA-3 — Service JWT ngắn hạn ký bởi Identity & Access + giữ nguyên security group** *(đề xuất SA)* | Mỗi service tự xin "service token" (JWT riêng, `sub=service-name`, TTL ngắn ~5 phút) từ Identity & Access qua IAM role (không cần secret tĩnh), đính kèm header khi gọi `IF-006`/`IF-021`/`IF-022`; bên nhận verify chữ ký giống verify JWT người dùng (tái dùng hạ tầng ký/verify đã có) | Không cần hạ tầng mới ngoài quy ước header + logic verify (tái dùng key JWT của `CMP-02`); tương thích với ghi chú "không thêm hạ tầng mới" của `SAD` | Cần Identity & Access cấp phát token cho service (thêm luồng nội bộ mới, nhỏ); vẫn phụ thuộc network layer làm lớp phòng thủ đầu (không phải mTLS full zero-trust) | **Đề xuất SA: PA-3**, vì tương thích với ràng buộc đã ghi ở `SAD §7` v1.2 (không thêm hạ tầng mới ở lượt này) trong khi vẫn nâng được một lớp phòng thủ so với hiện trạng thuần network. Ước lượng radar theo `decision-radar.md §2`: chi phí đảo ngược trung bình (đổi cơ chế sau khi đã code tốn sửa cả hai đầu gọi)=1 · bán kính: mọi lời gọi cross-network nội bộ (TB3, TB4) + tiền lệ cho các `IF` tương lai=2 · chạm gián tiếp `QAS-002`/`QAS-010` (thêm bước xin token có thể ăn vào ngân sách latency đã eo hẹp, cần đo lại)=1 · ràng buộc ≥1 năm (chuẩn nội bộ cho service-to-service)=1 · chưa tranh cãi=0 → **~5, ở ngưỡng "ADR bắt buộc"**. Xem [`adr/ADR-015_service-jwt-xac-thuc-service-to-service.md`](adr/ADR-015_service-jwt-xac-thuc-service-to-service.md) (`Proposed`, viết ở hoạt động `adr` kế tiếp). `OQ-050` **giữ nguyên mở** — chặn cứng bởi `OQ-007` (Security chưa có người được chỉ định; ADR bảo mật chỉ chuyển `Accepted` khi có Security thật ký, xem `ADR-015 §0`/§3). 🔴 Đây là quyết định chạm cả `QAS-002` (latency) lẫn ranh giới hạ tầng — `ADR-015` ghi rõ điều kiện `Accepted` cần cả Tech Lead lẫn Security (phủ quyết) cùng xác nhận trước khi chốt. --- ## 3. Phân quyền (Authorization) | | Quyết định | `ADR` | |---|---|---| | **Mô hình** | RBAC đơn giản (2 vai trò trong phạm vi Cart&Checkout: Guest, Customer) + ABAC nhẹ cho ownership (đối chiếu `session_id`/`customer_id` với dữ liệu) | `ADR-007` | | **Chỗ ra quyết định** | **Service** (Cart & Order tự kiểm tra), **không phải** gateway — `CMP-01` chỉ chuyển token/session xuống, đúng `SAD §4.1` | `ADR-007` | | **Nguồn sự thật của vai trò** | Identity & Access (`CMP-02`) — `role` claim trong JWT (Customer/Seller/Admin); Guest không có "vai trò" theo nghĩa RBAC, chỉ có `session_id` | `CMP-02` | | **Ràng buộc dữ liệu (row-level)** | Có — ownership theo `customer_id`/`session_id`, cache Redis TTL ngắn, fallback query DB khi cache miss | `ADR-007` | | **Hành vi khi không xác định được quyền (lỗi kỹ thuật, không phải "không có quyền")** | **Fail-closed** — trả `503` (không phải `403`), mã lỗi đề xuất `E-CART-0007` (theo `FAIL §5`, chưa có trong `SRS`/`API` của BA — `OQ-040`) khi cả Redis lẫn DB đều lỗi lúc kiểm tra ownership. **Không bao giờ mặc định cho phép truy cập khi không kiểm tra được** | `FAIL FM-06`, `OQ-040` | 🔴 **Fail-closed là quyết định bảo mật, không phải quyết định hiệu năng** — nếu Tech Lead/Dev sau này "tối ưu" bằng cách coi lỗi kỹ thuật = cho phép (fail-open) để giảm tỷ lệ lỗi 503, đó là một lỗ hổng nghiêm trọng (bất kỳ ai cũng xem được giỏ/đơn của người khác khi hệ thống đang có sự cố). Ghi rõ ở đây để Security có căn cứ phủ quyết nếu phát hiện vi phạm khi review code. ### 3.1 Map `RBAC` của bộ BA xuống quyền kỹ thuật *`RBAC_CartCheckout_v1.0.md §1` chỉ có 2 `ROLE-nn` trong phạm vi module này (Seller/Admin/CSR/Ops cố ý không đưa vào — xem `RBAC §1`). Cả 2/2 đã có dòng dưới đây — đủ điều kiện không chặn AG2 ở mục này.* | `ROLE-nn` (BA) | Vai trò kỹ thuật | Claim/định danh | Quyền trên `IF-nnn` | Ràng buộc dữ liệu | Ai gán vai trò này | |---|---|---|---|---|---| | `ROLE-01` Guest | `guest` (không có tài khoản, không JWT) | Header `X-Guest-Session-Id` (§2.1) | `IF-002` — `GET`/`PATCH`/`DELETE /v1/cart*`, `POST /v1/checkout` | 🔶 **chỉ `Cart`/`Order` có `session_id` = giá trị header hiện tại** — đối chiếu tại service (`ADR-007`), fail-closed nếu không kiểm tra được (`E-CART-0007`) | Hệ thống tự tạo tại lần truy cập đầu tiên chưa đăng nhập — không ai "gán", không cần phê duyệt | | `ROLE-02` Customer | `customer` (JWT `role=customer`) | `sub` = `customerId` trong JWT (§2.2) | `IF-002` — cùng 4 endpoint như Guest | 🔶 **chỉ `Cart`/`Order` có `customer_id` = `sub`** — đối chiếu tại service, fail-closed tương tự | Identity & Access (`CMP-02`) tự động khi đăng ký/đăng nhập thành công — self-service, không cần phê duyệt nội bộ | *Seller (`FR-19`, module Quản lý đơn hàng seller) và Admin/CSR/Ops (không có hành động trực tiếp trong RQ-001…004) **ngoài phạm vi** map này theo đúng `RBAC_CartCheckout §1` — sẽ có `RBAC`/map riêng khi module tương ứng tới lượt thiết kế chi tiết. `ASR-009` (MFA Admin) vẫn áp dụng xuyên suốt bất kể module nào Admin thao tác (xem §2.3).* ### 3.2 Phân tách nhiệm vụ (SoD) *Kế thừa nguyên trạng kết luận của `RBAC_CartCheckout §3` (BA): **không áp dụng được** trong phạm vi module này — mọi hành động (tạo giỏ, tách đơn, chọn thanh toán) là tự phục vụ do chính khách hàng thực hiện trên dữ liệu của họ, không có bước "người thứ hai duyệt". Việc tách đơn (`BR-CART-01`) và xác nhận thanh toán (`BR-CART-06`) do hệ thống tự động thực hiện theo rule, không phải nhân sự nội bộ phê duyệt.* | Hành động | Người thực hiện không được đồng thời là | Cơ chế cưỡng chế | |---|---|---| | *(không có trong phạm vi module Giỏ hàng & Checkout — SoD sẽ cần thiết khi module Quản lý đơn hàng có bước Seller/CSR/Admin can thiệp thủ công, VD duyệt hoàn tiền — ngoài phạm vi tài liệu này)* | | | --- ## 4. Threat model — STRIDE *Theo 8 ranh giới tin cậy ở §1. Mỗi `THR-nn`: loại STRIDE · tài sản bị nhắm · biện pháp · cách kiểm chứng · truy vết `QAS`/`ASR`/`ADR`.* ### 4.1 TB1 — Client ↔ ALB/WAF | ID | Loại (STRIDE) | Mối đe doạ | Thành phần bị nhắm | Mức | Biện pháp | Cách kiểm chứng | Truy vết | |---|---|---|---|---|---|---|---| | `THR-01` | Spoofing | Đánh cắp JWT/session qua XSS hoặc MITM (nếu TLS bị hạ cấp) | Token Customer, session Guest | 🔴 | TLS 1.2+ bắt buộc + HSTS; access token khuyến nghị giữ trong memory (SPA), không `localStorage`; cookie Guest `HttpOnly;Secure;SameSite=Lax` (đã có, `ICD §1`) | Test cấu hình TLS/HSTS tự động (`FIT-33` ứng viên) + code review chỗ lưu token phía FE | `QAS-010`, `ASR-007` | | `THR-02` | Tampering | Client gửi giá/số lượng đã bị sửa (tamper qua devtools) để checkout giá thấp hơn | `POST /v1/checkout` request body | 🟠 | Server luôn tính giá/tổng từ `product_variant.price_amount`/`unit_price_snapshot` phía BE, **không tin** giá trị giá do client gửi (đã đúng thiết kế `ICD`, không phát hiện lỗ hổng cụ thể) | Test gửi giá giả trong payload, xác nhận BE bỏ qua và tự tính lại | `ASR-003`, `ADR-003` | | `THR-04` | Information disclosure | TLS downgrade / lộ thông tin qua response header thừa (server banner, stack trace) | Toàn bộ traffic + response lỗi | 🟠 | HSTS, ẩn header `Server`/version; response `500` không bao giờ trả chi tiết exception, chỉ `traceId` (đã đúng thiết kế `ICD §1` mục 4) | Scan cấu hình TLS (SSL Labs-style) định kỳ; test gọi lỗi 500 xác nhận không rò rỉ stack trace | — | | `THR-05` | Denial of Service | Volumetric/L7 flood tại biên (trước khi tới ứng dụng) | `CMP-01` WAF/ALB, toàn bộ hệ thống phía sau | 🟠 | WAF rate-based rule + AWS Shield Standard (mặc định có với CloudFront/ALB); rate-limit theo IP ở tầng WAF trước khi request chạm ứng dụng | Load test giả lập burst traffic trên staging (ứng viên `FIT`, ngoài phạm vi diễn tập GĐ2) | `QAS-009` | ### 4.2 TB2 — ALB → Nhóm Giao dịch (ownership/IDOR) | ID | Loại (STRIDE) | Mối đe doạ | Thành phần bị nhắm | Mức | Biện pháp | Cách kiểm chứng | Truy vết | |---|---|---|---|---|---|---|---| | `THR-06` | Spoofing | Guest session id bị đoán (nếu CSPRNG yếu) hoặc bị lộ qua log/URL | `X-Guest-Session-Id` | 🔴 | CSPRNG ≥128-bit (đã chốt `ICD §1` mục 10); **cấm** đưa session id vào query string/URL (chỉ header/cookie); log-scrubber không ghi giá trị đầy đủ | Test entropy giá trị sinh ra; grep log staging xác nhận không xuất hiện session id đầy đủ | `QAS-010` | | `THR-07` | Elevation of Privilege | IDOR — request giả mạo `cartItemId`/`orderId` không phải chủ sở hữu | `CMP-04` mọi endpoint `IF-002` | 🔴 | Ownership check bắt buộc tại service (`ADR-007`), 0% bypass, fail-closed khi lỗi kỹ thuật (`E-CART-0007`) | Integration test tự động gọi API với token/session không phải chủ sở hữu — 0 lượt thành công (đã có ở `QAS-010`, tương ứng `AC-US003-12/13`) | `QAS-010`, `ASR-007`, `ADR-007` | | `THR-08` | Denial of Service | Guest lạm dụng `PATCH`/`DELETE /v1/cart/items` (spam thêm/xoá liên tục) để tiêu tốn tài nguyên hoặc thao túng tồn kho reserve | `CMP-04`, `CMP-03` (reserve tồn kho) | 🟠 | Rate limit theo IP + `session_id` — xem đề xuất số cụ thể ở §5.3 (`OQ-023`) | Test gửi burst request vượt ngưỡng, xác nhận `429` | `RBAC_CartCheckout §8` `OQ-015` (BA) | ### 4.3 TB3 — Nhóm Giao dịch ↔ Nhóm Hỗ trợ (`IF-021`/`IF-022`, cross-network) | ID | Loại (STRIDE) | Mối đe doạ | Thành phần bị nhắm | Mức | Biện pháp | Cách kiểm chứng | Truy vết | |---|---|---|---|---|---|---|---| | `THR-09` | Spoofing | Không có xác thực danh tính bên gọi — bất kỳ tiến trình nào trong VPC có thể giả danh Cart & Order gọi `IF-021`/`IF-022` nếu security group không chặt | `CMP-07`, `CMP-05` | 🔴 | Service JWT ngắn hạn — [`ADR-015`](adr/ADR-015_service-jwt-xac-thuc-service-to-service.md) (`Proposed`, **chưa `Accepted`** — chặn bởi `OQ-007`/`OQ-050`) | Chưa kiểm chứng được — chặn bởi `ADR-015` chưa `Accepted` | `OQ-050`, `ADR-015` | | `THR-10` | Tampering | Payload `IF-021` (áp dụng coupon) bị giả mạo giá trị giảm giá vượt hợp lệ nếu Promotion&Loyalty không validate chặt | `CMP-07` | 🟠 | Validate bounds: giá trị giảm ≥0 và ≤ tổng tiền đơn hàng (đã ghi ở `FAIL §2` `FM-12` câu hỏi 3) | Test gửi giá trị giảm âm/vượt tổng, xác nhận bị từ chối | `FAIL FM-12` | | `THR-11` | Information disclosure | `IF-022` trả nhầm thông tin seller khác (nếu logic tra cứu sai `seller_id`) hoặc lộ PII khách hàng nếu tương lai `IF-022` đổi chiều mang theo dữ liệu khách | `CMP-05` | 🟠 | Denormalize `sellerName` snapshot (không JOIN ngược runtime, `ICD §3.7`) giảm bề mặt; nếu vẫn cần gọi runtime, kiểm tra input `seller_id` khớp đúng `OrderSeller` đang xử lý | Contract test xác nhận response chỉ chứa đúng trường mong đợi | `OQ-032`, `OQ-033` | | `THR-12` | Denial of Service | Retry storm/cascading failure — Nhóm Hỗ trợ chậm/hỏng kéo theo Cart&Order giữ tài nguyên (đã phân tích ở `FAIL FM-12`) | `CMP-04`, `CMP-07` | 🟠 | Circuit breaker cho `IF-021` (đã thiết kế `FAIL §3.1`), 0 retry trong đường găng checkout | Chaos test giả lập `IF-021` timeout liên tục, xác nhận circuit breaker mở đúng ngưỡng (`FIT-19`, đã có ở `FAIL`) | `FAIL FM-12`, `QAS-002` | ### 4.4 TB4 — Cart & Order ↔ Payment (`IF-006`) | ID | Loại (STRIDE) | Mối đe doạ | Thành phần bị nhắm | Mức | Biện pháp | Cách kiểm chứng | Truy vết | |---|---|---|---|---|---|---|---| | `THR-13` | Spoofing | Không có xác thực danh tính — một service khác trong VPC có thể giả danh Cart & Order để khởi tạo `Payment` giả | `CMP-11` | 🔴 | Cùng biện pháp `THR-09` — [`ADR-015`](adr/ADR-015_service-jwt-xac-thuc-service-to-service.md) (`Proposed`). **Đây là ranh giới nhạy cảm nhất (tiền thật)** — ưu tiên xử lý cao nhất, `ADR-015` chưa `Accepted` | Chưa kiểm chứng được — chặn bởi `ADR-015` chưa `Accepted` | `ASR-002`, `OQ-050`, `ADR-015` | | `THR-14` | Tampering | `amountVnd` trong request `IF-006` không khớp `OrderSeller.subtotal_amount` thật (do bug hoặc bên gọi bị compromise) | `CMP-11` | 🔴 | Payment Service phải **tự đối chiếu lại** `amountVnd` nhận được với giá trị tính từ `OrderSeller` (không tin tưởng tuyệt đối request đến, dù cùng nội bộ) — 🔴 **chưa được `ICD §3.3` ghi nhận là bước bắt buộc**, đề xuất bổ sung ở lượt `icd`/`dat` kế tiếp | Test gửi `amountVnd` sai lệch, xác nhận Payment Service từ chối thay vì tin theo | `ADR-002`, `ADR-003` | | `THR-15` | Repudiation | Không truy vết được ai/service nào đã trigger một `Payment` cụ thể nếu thiếu correlation id | `CMP-11` | 🟡 | `X-Request-Id` (`OQ-031`) xuyên suốt + audit log ghi `actor`/`correlation_id` (§7) | Kiểm tra log Payment Service có `correlation_id` khớp với log Cart & Order cho cùng giao dịch | `OQ-031` | | `THR-16` | Elevation of Privilege | Module khác (ngoài Payment) cố truy cập trực tiếp RDS Payment (bỏ qua `IF-006`/`IF-017`) | `CMP-14` | 🔴 | Network/IAM cô lập hoàn toàn (`ADR-002`) — không security group nào khác được phép kết nối `RDS Payment` | Kiểm tra hạ tầng: Terraform plan/AWS Config rule xác nhận không có security group nào khác trỏ tới RDS Payment (đã có `FIT-03` ở `ADR-002`) | `ASR-002`, `ADR-002`, `FIT-03` | ### 4.5 TB5 — Payment ↔ VNPay/Momo (init sync + webhook inbound async) | ID | Loại (STRIDE) | Mối đe doạ | Thành phần bị nhắm | Mức | Biện pháp | Cách kiểm chứng | Truy vết | |---|---|---|---|---|---|---|---| | `THR-17` | Spoofing | Webhook IPN giả mạo (kẻ tấn công tự gọi endpoint webhook giả lập giao dịch thành công) | `CMP-11`, `payment.status` | 🔴 | Xác thực chữ ký/HMAC theo tài liệu VNPay/Momo — **🔴 chưa có tài liệu/sandbox thật, không bịa cơ chế cụ thể** (`ARISK-03`). Đề xuất SA: từ chối cứng mọi webhook không xác minh được chữ ký hợp lệ, **không** xử lý "tạm chấp nhận rồi kiểm tra sau" | 🔴 **Chưa kiểm chứng được** — chặn bởi thiếu sandbox. Khi có sandbox: test gửi webhook chữ ký sai, xác nhận bị từ chối và ghi log cảnh báo (khả năng giả mạo, không coi là lỗi hệ thống thường — đã ghi ở `FAIL §2` `FM-01/02`) | `ADR-004`, `ARISK-03`, `OQ-049` | | `THR-18` | Tampering | Replay webhook cũ (gửi lại payload hợp lệ đã xử lý trước đó để trigger lại logic) | `CMP-11` | 🟠 | Idempotency theo `gatewayTransactionRef` (`ADR-004`) + kiểm tra `timestamp` payload lệch ≤5 phút (`ICD §1` mục 12) — đã xử lý cả 2 lớp (idempotent + chống replay theo thời gian) | Test gửi lại đúng webhook cũ ngoài cửa sổ 5 phút, xác nhận bị từ chối; gửi lại trong cửa sổ, xác nhận idempotent (không xử lý lại nghiệp vụ) | `ADR-004`, `QAS-014` | | `THR-19` | Information disclosure | `gateway_response_snapshot` vô tình chứa dữ liệu thẻ nếu gateway trả về ngoài dự kiến | `payment_transaction.gateway_response_snapshot` (`DAT §2.1`) | 🔴 | Whitelist field được lưu trước khi ghi (lọc bỏ mọi trường không nằm trong danh sách kỳ vọng, **mặc định từ chối lưu trường lạ** thay vì mặc định chấp nhận) — đề xuất mới, chưa có trong `DAT` hiện tại | Test giả lập gateway trả thêm trường lạ (VD số thẻ rút gọn), xác nhận không được ghi vào `gateway_response_snapshot` | `ASR-002`, `BR-CART-05` (BA) | | `THR-20` | Repudiation | Không phát hiện được giao dịch bị VNPay/Momo báo sai trạng thái (báo `success` nhưng thực tế tiền chưa về, hoặc ngược lại) | `payment.status` | 🟠 | Job đối soát bù định kỳ ≤15 phút (`ADR-004`, `QAS-014`) — không tự động sửa, chỉ ghi `ReconciliationLog` + cảnh báo | Test giả lập webhook trễ/mất trên staging (cần sandbox thật để đầy đủ — `FIT-21`, đã có ở `FAIL`) | `ADR-004`, `QAS-014` | | `THR-21` | Denial of Service | Webhook flooding (đối tác hoặc kẻ tấn công gửi số lượng lớn webhook giả) | `CMP-11` | 🟡 | Rate limit endpoint webhook theo nguồn IP đối tác đã biết (whitelist IP nếu đối tác công bố dải IP cố định — 🔴 chưa xác nhận, `OQ-049`); WAF chung ở TB1 vẫn áp dụng | Load test endpoint webhook trên staging | `ARISK-03` | ### 4.6 TB6 — Shipping & Fulfillment ↔ GHN/GHTK webhook | ID | Loại (STRIDE) | Mối đe doạ | Thành phần bị nhắm | Mức | Biện pháp | Cách kiểm chứng | Truy vết | |---|---|---|---|---|---|---|---| | `THR-22` | Spoofing | Webhook cập nhật trạng thái vận chuyển giả mạo | `CMP-10`, `shipment.status` | 🟠 | Chữ ký/token theo tài liệu GHN/GHTK — **🔴 chưa có tài liệu/sandbox thật** (`ARISK-04`), không bịa cơ chế cụ thể | Chưa kiểm chứng được — chặn bởi thiếu sandbox | `ARISK-04`, `OQ-049` | | `THR-23` | Tampering | Trạng thái vận đơn "thụt lùi" (từ "đang giao" về "đã tạo đơn") do webhook lỗi/giả mạo | `shipment.status` | 🟡 | Không ghi đè khi trạng thái mới "thụt lùi" so với trạng thái tiến bộ nhất đã ghi (đã thiết kế ở `FAIL §2` `FM-03/04`), cảnh báo Ops kiểm tra thủ công | Test gửi webhook trạng thái thụt lùi, xác nhận không ghi đè | `FAIL FM-03/04` | ### 4.7 TB7 — App ↔ RDS/Redis/SQS | ID | Loại (STRIDE) | Mối đe doạ | Thành phần bị nhắm | Mức | Biện pháp | Cách kiểm chứng | Truy vết | |---|---|---|---|---|---|---|---| | `THR-24` | Information disclosure | Một module đọc/ghi nhầm schema của module khác trong cùng RDS chính (schema-per-module nhưng chung instance/IAM lỏng lẻo) | `CMP-13` (8 schema) | 🟠 | IAM DB role riêng theo module, chỉ cấp quyền đúng schema của module đó (Postgres role + `GRANT` theo schema) — 🔴 **chưa được `DAT`/`ADR-006` xác nhận chi tiết cấp quyền**, đề xuất bổ sung ở `inf` | Kiểm tra `GRANT`/role Postgres qua migration review; test connection dùng role module A cố `SELECT` schema module B, xác nhận bị từ chối | `ADR-006`, `D7` | | `THR-25` | Tampering | Producer không hợp lệ (service bị compromise hoặc external actor với network access) publish message giả vào SQS/EventBridge | `CMP-12` | 🟠 | IAM policy giới hạn `sqs:SendMessage`/`events:PutEvents` chỉ cho ECS task role của `CMP-04`/`CMP-11` (publisher hợp lệ duy nhất); consumer validate schema (`eventVersion`, field bắt buộc) trước khi xử lý, message không hợp lệ → DLQ (đã có ở `FAIL §2` `FM-09/10`) | Kiểm tra IAM policy qua Terraform plan; test publish message sai schema, xác nhận route DLQ | `ADR-005`, `FAIL FM-09/10` | | `THR-26` | Information disclosure | Kết nối Redis không mã hoá in-transit trong VPC (nếu VPC bị compromise, traffic session/ownership cache có thể bị nghe lén) | `CMP-15` | 🟡 | Bật TLS in-transit cho ElastiCache Redis (encryption in-transit, tính năng có sẵn của AWS) — 🔴 **chưa xác nhận đã bật hay chưa trong cấu hình `INF` (chưa chạy)** | Kiểm tra cấu hình ElastiCache khi `inf` chạy | `INF` (hoạt động 7, chưa chạy) | | `THR-27` | Denial of Service | Một module (đọc nặng, VD Catalog search) chiếm hết connection pool RDS chung, chặn module ghi (checkout) | `CMP-13` | 🟠 | Bulkhead — connection pool riêng theo module (đã ghi nhận ở `FAIL §3.3`, kích thước cụ thể chờ `POC-02`, `OQ-037`) | Load test saturate pool 1 module, xác nhận module khác không bị ảnh hưởng (`FIT-22`, đã có ở `FAIL`) | `FAIL FM-06`, `OQ-037` | ### 4.8 TB8 — Admin console | ID | Loại (STRIDE) | Mối đe doạ | Thành phần bị nhắm | Mức | Biện pháp | Cách kiểm chứng | Truy vết | |---|---|---|---|---|---|---|---| | `THR-28` | Spoofing | Đánh cắp/dò mật khẩu Admin (không có MFA bypass path) | `CMP-02` (Admin) | 🔴 | MFA bắt buộc TOTP (`ASR-009`), account lockout sau 3 lần sai (§2.3, đề xuất) | Test đăng nhập Admin không qua MFA, xác nhận bị từ chối (đã có ở `QAS-012`) | `QAS-012`, `ASR-009` | | `THR-29` | Elevation of Privilege | Thiếu kiểm tra scope/role dẫn tới Customer/Seller gọi được endpoint Admin | `CMP-02` và mọi endpoint quản trị | 🔴 | Middleware kiểm tra `role`/scope claim bắt buộc trước business logic (nguyên tắc chung, tham khảo ý tưởng P1 `docs/08 §8.1.2`, tự quyết định lại cho P2 vì P2 không có OPA/BFF riêng như P1) | Test gọi endpoint Admin bằng JWT `role=customer`, xác nhận `403` | `ASR-009` | | `THR-30` | Repudiation | Hành động Admin (khoá tài khoản, duyệt seller...) không được ghi vết | Toàn hệ thống, đặc biệt module ngoài phạm vi US-002/003 | 🟠 | `audit_log` bắt buộc cho mọi hành động Admin nhạy cảm (§7) | Kiểm tra coverage: mọi endpoint `role=admin` ghi được ≥1 dòng `audit_log` tương ứng (`FIT-32` mới) | `RBAC_CartCheckout §5` | | `THR-31` | Denial of Service | Brute-force đăng nhập Admin (dò mật khẩu hàng loạt) | `/v1/auth/login` (Admin) | 🟠 | Account lockout (§2.3) + rate-limit theo IP (§5.3) + captcha sau N lần sai (tham khảo ý tưởng P1, chưa chốt ngưỡng cho P2) | Test brute-force giả lập, xác nhận khoá đúng ngưỡng | `OQ-052` | ### 4.9 Mối đe doạ đã chấp nhận | `THR` | Vì sao chấp nhận | Ai ký · ngày | Dấu hiệu cảnh báo | Kế hoạch nếu xảy ra | |---|---|---|---|---| | *(chưa có mục nào — Security chưa có người để ký chấp nhận rủi ro, `OQ-007`. Không tự chấp nhận rủi ro thay Security theo `D10`.)* | | | | | 🔴 **Tổng kết:** 31 `THR` được liệt kê (`THR-01…31`, một số ID không liên tục do rà soát nhóm theo STRIDE không đều ở mỗi ranh giới — không có ID nào bị bỏ trống ngầm). **Bốn nhóm mức 🔴 cao nhất chưa có biện pháp đủ**: (1) `THR-09`/`THR-13` — thiếu service-to-service authn ở TB3/TB4 (§2.4, `OQ-050`); (2) `THR-17`/`THR-22` — chữ ký webhook thật chưa xác nhận được vì thiếu sandbox đối tác (`OQ-049`, `ARISK-03/04`); (3) `THR-19` — lọc trường `gateway_response_snapshot` chưa triển khai; (4) mọi threat liên quan PII (`THR-11` gián tiếp) phụ thuộc `OQ-007` chưa có người phủ quyết. --- ## 5. Bảo vệ dữ liệu 🔴 **Toàn bộ mục này (§5) là ĐỀ XUẤT của SA, CHƯA CÓ HIỆU LỰC PHỦ QUYẾT** — Security/Pháp chế chưa có người được chỉ định (`OQ-007`, mở từ GĐ1, kế thừa `RISK-03` của BA). Không coi bất kỳ dòng nào dưới đây là quyết định cuối cùng. ### 5.1 Phân loại & mã hoá *Kế thừa nguyên trạng phân loại đã có ở `DAT_e-commerce_v1.0.md §5` (không lặp lại toàn bộ bảng — tham chiếu bằng đường dẫn theo `D` "không copy nội dung giữa các tài liệu"). SEC xác nhận lại góc độ bảo mật/kiểm chứng cho từng nhóm:* | Nhóm dữ liệu | Mã hoá at-rest | Mã hoá in-transit | Che khi hiển thị | Che khi log | Nguồn phân loại | |---|---|---|---|---|---| | Danh tính & liên hệ khách hàng (`email`/`phone`/`full_name`) | RDS KMS mặc định (đề xuất `DAT §5`) | TLS 1.2+ mọi kết nối (§1) | Không che với chính chủ; không hiển thị cho seller | **Bắt buộc** — log-scrubber mask `email`/`phone` (đề xuất mới, tham khảo ý tưởng P1 `docs/08 §8.2.3`, tự quyết định lại) | `DAT §5` | | Địa chỉ giao hàng (`recipient_name`/`phone`/`address_line`) | RDS KMS | TLS 1.2+ | **Whitelist cho seller** — chỉ 3 trường trên, đúng `OrderSeller` liên quan (`ADR-008` PA-2, đề xuất) — 🔴 **mức che (full hay một phần) chưa chốt**, xem `OQ-053` (mới) | Bắt buộc mask trong log ứng dụng | `DAT §5`, `RBAC §4` | | KYC seller (`file_url_s3`, `tax_code`, `business_license_number`) | S3 SSE-KMS + RDS KMS; đề xuất mã hoá tầng ứng dụng bổ sung (tham khảo ý tưởng P1 `docs/08 §8.2.1`) | TLS 1.2+ | Chỉ Admin/CSR đã duyệt xem (ngoài phạm vi module này) | Không log giá trị đầy đủ; nếu cần audit, mask giữ vài ký tự đầu/cuối (tham khảo ý tưởng P1 `docs/08 §8.2.5a`) | `DAT §5` | | Tài khoản ngân hàng seller (`account_number`) | **Bắt buộc mã hoá tầng ứng dụng** (không chỉ KMS) | TLS 1.2+ | Che một phần khi hiển thị (VD `****1234`) | Che hoàn toàn, không log giá trị | `DAT §5` | | Dữ liệu thanh toán (`payment.amount`, `gateway_transaction_ref`, `gateway_response_snapshot` đã lọc) | RDS KMS (RDS Payment riêng, `ADR-002`) + đề xuất mã hoá tầng ứng dụng cho `gateway_transaction_ref` | TLS 1.2+, RDS Payment mạng riêng | Chỉ hiển thị tham chiếu rút gọn cho khách | **Tuyệt đối không log** `gateway_response_snapshot` thô ở mức DEBUG production | `DAT §5`, `ADR-002` | | Dữ liệu nghiệp vụ công khai (`product`, `category`, `review`) | RDS KMS mặc định | TLS 1.2+ | Không cần che | Không cần che | `DAT §5` | 🔴 **Dữ liệu production trên môi trường dev/staging bị cấm tuyệt đối** — đúng nguyên tắc template mục 5. Yêu cầu quy trình anonymize khi sao chép Production → Staging (hash/mask `email`/`phone`, xoá `tax_code`/`account_number` thật, thay bằng dữ liệu giả lập nhất quán) — **chưa có quy trình cụ thể cho P2**, đề xuất tham khảo ý tưởng P1 (`docs/08 §8.2.3`), ghi nhận là việc cần làm ở hoạt động `inf` (§7 non-prod topology). ### 5.2 Whitelist chia sẻ PII cho seller — hiện thực hoá `ADR-008` PA-2 *Đúng như `ADR-008` (Proposed, chờ Security/Legal) và `DAT §5.2` đã thiết kế: `order_seller` chỉ lưu snapshot đúng 3 trường (`recipient_name`, `phone`, `address_line`) — không JOIN ngược sang schema `identity`. SEC xác nhận lại từ góc độ threat model: đây là biện pháp giảm bề mặt rủi ro đúng (`THR-11`), nhưng bản thân việc "3 trường này có nên hiển thị đầy đủ hay che một phần cho seller" **vẫn là câu hỏi mở** — xem `OQ-053`.* 🔴 **Nếu Security/Legal từ chối PA-2 khi có người ký, toàn bộ §5.1/§5.2 và cơ chế denormalize ở `DAT §5.2`/`ICD §3.7` phải thiết kế lại** — đây là rủi ro kiến trúc đã ghi nhận ở `ADR-008 §3`, không phải điều mới phát hiện ở `sec`. ### 5.3 Đề xuất rate limit — trả lời `OQ-023` *🔴 `OQ-023` yêu cầu: "SEC đề xuất số cụ thể + hệ quả, không tự quyết thay Security." Bảng dưới là **đề xuất**, Security là người chốt cuối.* | Endpoint/hành động | Ngưỡng đề xuất | Đơn vị đếm | Hệ quả nếu Security chọn CHẶT hơn | Hệ quả nếu Security chọn LỎNG hơn | |---|---|---|---|---| | `PATCH`/`DELETE /v1/cart/items` (Guest) | **30 request/phút** | Theo `session_id` (chính) + 60 req/phút theo IP (phòng vệ phụ, chống một IP tạo nhiều session để né giới hạn theo session) | VD 10/phút: giảm mạnh khả năng spam/thao túng tồn kho reserve, nhưng có thể chặn nhầm khách thao tác nhanh trên UI (VD sửa số lượng nhiều dòng liên tiếp) — tăng khiếu nại trải nghiệm | VD 100/phút: giảm false positive, nhưng dễ bị lạm dụng để giữ/giải phóng tồn kho reserve liên tục (làm nhiễu `inventory_stock`, ảnh hưởng gián tiếp trải nghiệm khách thật muốn mua) | | `POST /v1/checkout` | **10 request/phút** theo `session_id`/`customer_id` | Theo định danh (Guest: session, Customer: customer_id) | VD 3/phút: an toàn hơn trước spam tạo đơn giả (`RBAC §8` `OQ-015` của BA), nhưng khách thao tác thật thử lại nhiều lần sau lỗi 4xx/5xx có thể bị chặn oan | VD 30/phút: giảm false positive khi khách retry sau lỗi mạng, nhưng tăng rủi ro spam tạo `Order`/giữ tồn kho reserve hàng loạt | | `POST /v1/auth/login` (mọi vai trò) | **10 request/phút theo IP** (độc lập với account lockout §2.3, đây là lớp phòng thủ theo IP) | Theo IP | VD 3/phút: chống brute-force mạnh hơn, nhưng ảnh hưởng người dùng chung IP NAT (mạng công ty/quán net Việt Nam khá phổ biến) | VD 50/phút: giảm false positive NAT, nhưng làm yếu lớp phòng thủ IP (vẫn còn account lockout §2.3 làm lớp thứ hai) | | Webhook inbound (`IF-007`/`IF-008`/`IF-018`/`IF-019`) | Không giới hạn cứng theo request/phút (đối tác tự quyết định tần suất gọi lại) — chỉ giới hạn ở WAF chung (TB1) chống flood bất thường | — | — | — | 🔴 **Ba con số trên (30, 10, 10) là ước lượng SA dựa trên hành vi UI thông thường (không có dữ liệu traffic thật, `greenfield`)** — không phải kết quả đo. Security cần xác nhận hoặc điều chỉnh dựa trên khẩu vị rủi ro thật của tổ chức. --- ## 6. Quản lý secret | | Quyết định | |---|---| | Nơi lưu | **AWS Secrets Manager** cho: DB credentials (RDS chính + RDS Payment, **secret riêng biệt**, không chung), API key/secret VNPay/Momo/GHN/GHTK, JWT signing key (`CMP-02`), SMTP/SMS provider key (khi có nhà cung cấp, `OQ-016` của `TCO`) | | Cách ứng dụng lấy | ECS task role (IAM) có quyền `secretsmanager:GetSecretValue` **chỉ đúng secret của module đó** — không task nào được đọc secret của module khác (đối xứng với nguyên tắc cô lập schema §4.7) | | Xoay khoá: tần suất, tự động hay thủ công | DB credentials: **tự động** (AWS Secrets Manager rotation Lambda, chu kỳ đề xuất 30 ngày — chưa Tech Lead xác nhận); API key đối tác ngoài: **thủ công**, chu kỳ đề xuất 90 ngày (phụ thuộc khả năng hỗ trợ rotation của từng đối tác — 🔴 chưa xác nhận VNPay/Momo/GHN/GHTK có hỗ trợ rotate key không, `ARISK-03/04`); JWT signing key: xoay 90 ngày, dùng `kid` để hỗ trợ 2 khoá song song (§2.2) | | **Cấm tuyệt đối** | Secret trong mã nguồn/Git, secret trong biến môi trường bị ghi vào log (log-scrubber phải chặn pattern giống secret), secret trong ảnh container (build-time bake) | | Cách phát hiện rò rỉ | Quét mã nguồn trong CI/CD (Gitleaks/TruffleHog) — chặn merge nếu phát hiện secret pattern; `FIT-29` (mới, ứng viên GĐ3) | --- ## 7. Audit log *Theo phương án (a) đã chốt TẠM ở `OQ-047`/`DEC-25` (`DAT`): **mỗi module tự ghi `audit_log` trong schema của mình**, KHÔNG có `CMP-16` Audit tập trung. SEC chốt trường bắt buộc + retention + chống sửa cho quy ước chung áp dụng mọi module.* | Hành động phải ghi | Ghi những trường gì | Ai đọc được | Giữ bao lâu | Chống sửa bằng cách nào | |---|---|---|---|---| | Tạo `Order`/`OrderSeller` (checkout) | `actor_type` (guest/customer)· `actor_id` (`customer_id`/`session_id`) · `action` · `resource_type`/`resource_id` · `ip_address` · `correlation_id` (`X-Request-Id`, `OQ-031`) · `timestamp` (UTC) · `result` | Chính chủ đơn (qua tra cứu); nội bộ Kế toán/CSKH (module ngoài phạm vi US-002/003) | **10 năm** — nhất quán retention tài chính (`DAT §6`) | Bảng `append-only` — role ứng dụng chỉ có `INSERT`/`SELECT`, không `UPDATE`/`DELETE` (cưỡng chế ở DB role, không chỉ ở tầng code) | | Khởi tạo thanh toán / cập nhật `payment.status` | Tương tự trên + `payment_method`, `gateway_transaction_ref` (đã che theo §5.1) | Chính chủ đơn; nội bộ Kế toán | 10 năm | Tương tự trên (schema `payment`, RDS riêng theo `ADR-002`) | | Đăng nhập/thất bại (mọi vai trò) | `actor_id`, `role`, `ip_address`, `result` (success/fail), `timestamp`, `mfa_used` (bool) | Platform Admin (scope `admin:audit:read` — ý tưởng tham khảo P1, tự quyết định lại cho P2 vì chưa có endpoint đọc audit riêng) | 5 năm (đề xuất, tham khảo ý tưởng P1) | Append-only, schema `identity` | | Thay đổi quyền / khoá tài khoản (Admin) | `actor_id` (Admin thực hiện), `target_id`, `before`/`after` (redact trường nhạy cảm nếu có), `reason` (nếu có), `timestamp` | Platform Admin | 5 năm | Append-only, schema `identity` | | Truy cập dữ liệu nhạy cảm (VD Admin xem KYC document) | `actor_id`, `resource_type`/`resource_id`, `timestamp` — **không ghi nội dung tài liệu, chỉ ghi hành động xem** | Platform Admin | 5 năm | Append-only (module Seller Mgmt, ngoài phạm vi chi tiết US-002/003) | | Ownership check thất bại (IDOR bị chặn) | `actor_id`/`session_id`, `resource_type`/`resource_id` bị yêu cầu, `ip_address`, `timestamp` — phục vụ điều tra khi nghi ngờ tấn công hàng loạt | Security (khi có người) | 🔴 chưa chốt — đề xuất 1 năm, thấp hơn nhóm tài chính vì mục đích khác (an ninh vận hành, không phải bằng chứng giao dịch) | Append-only | 🔴 **Audit log mà người bị audit sửa được thì không phải audit log** — mỗi schema-per-module (`ADR-006`) phải cưỡng chế `append-only` ở mức DB role của chính schema đó, không có ngoại lệ cho `platform_admin` (Admin xem được nhưng không sửa/xoá được bản ghi audit). 🔴 **Khoảng trống đã biết:** không có `CMP` Audit tập trung (phương án (a)) nghĩa là **không có một nơi duy nhất** để Security truy vấn xuyên toàn sàn khi điều tra sự cố — mỗi module phải được truy vấn riêng. Đây là đánh đổi đã chấp nhận TẠM ở `DEC-25`, chưa Security thật xác nhận. Nếu Security khi có người yêu cầu audit tập trung, cần mở lại `OQ-047` và có thể đảo ngược sang phương án (b) (`CMP-16`) — chi phí đảo ngược: thêm 1 service mới + migrate log lịch sử từ N schema sang 1 nơi. --- ## 8. Tuân thủ ### 8.1 PCI-DSS SAQ A | Yêu cầu | Nguồn | Cách đáp ứng | Bằng chứng cho kiểm toán | Ai xác nhận | |---|---|---|---|---| | Không lưu PAN/CVV ở bất kỳ đâu ngoài Payment Service | `CON-06`, `BR-CART-05` (BA), `ADR-002` | `payment_transaction.gateway_response_snapshot` phải lọc trước khi ghi (`THR-19`); schema linter chặn cột kiểu "card_number"/"cvv" ở mọi schema khác `payment` | `FIT-04` (đã đề xuất ở `ADR-002`) | Security (chưa có người) | | Ranh giới mạng/IAM/dữ liệu cô lập hoàn toàn | `ASR-002`, `ADR-002` | Network diagram + IAM policy review; không security group nào khác trỏ tới RDS Payment | `FIT-03` (đã đề xuất ở `ADR-002`) | Security | | **Hình thức tích hợp VNPay/Momo phải là redirect, không nhúng iframe/form nhập thẻ trên domain sàn** *(đề xuất mới)* | Suy luận từ yêu cầu SAQ A (tham khảo `docs/08 §8.4`: "nếu redirect, scope tương ứng SAQ A") | **🔴 Chưa xác nhận được với VNPay/Momo thật** — chưa có tài liệu tích hợp, chưa biết họ có hỗ trợ redirect thuần hay bắt buộc SDK/iframe nào đó. Nếu chỉ hỗ trợ iframe/API pass-through dữ liệu thẻ, **toàn bộ giả định SAQ A của `ASR-002`/`ADR-002` phải xét lại** (có thể cần nâng cấp phạm vi tuân thủ, ảnh hưởng chi phí `TCO`) | — | Tech Lead + Security (`OQ-048`, mới) | | Webhook: chữ ký/HMAC theo tài liệu đối tác | `ADR-004` | 🔴 **Chưa biết cơ chế cụ thể** (SecureHash/HMAC-SHA256/khác) — không bịa, chờ tài liệu đối tác | `THR-17` | `OQ-049` (mới), `ARISK-03` | | Chống replay webhook | `ADR-004` | Kiểm tra `timestamp` payload lệch ≤5 phút (đã chốt, `ICD §1` mục 12) | `THR-18` | Đã đủ điều kiện kỹ thuật, chờ sandbox để kiểm chứng thật | | Quét lỗ hổng ASV hàng quý | `CON-06` | Nhà cung cấp ASV bên ngoài — 🔴 chưa có báo giá | Báo cáo ASV | Security (`OQ-017`, đã mở ở `TCO`) | | Pentest ứng dụng hàng năm | `CON-06` | Nhà cung cấp pentest bên ngoài — 🔴 chưa có báo giá | Báo cáo pentest | Security (`OQ-017`) | ### 8.2 NĐ13/2023 (Bảo vệ dữ liệu cá nhân) | Yêu cầu | Nguồn | Cách đáp ứng | Bằng chứng | Ai xác nhận | |---|---|---|---|---| | Data minimization khi chia sẻ PII cho seller | `ASR-008`, `QAS-011`, `ADR-008` | Whitelist 3 trường (§5.2) — **đề xuất, chưa hiệu lực** | Contract test (`FIT-11`, đã đề xuất ở `ADR-008`) | **Security/Legal — chưa có người (`OQ-007`)** | | Residency dữ liệu tại `ap-southeast-1` đáp ứng đủ yêu cầu | `CON-06`, `ASM-04` | 🔴 **Chưa xác nhận** — chỉ là giả định (`ASM-04`) | — | Legal (`OQ-007`) | | Quyền được xoá / ẩn danh hoá | `CON-06` | Đề xuất 30 ngày ẩn danh hoá kể từ yêu cầu hợp lệ (`DAT §5`) — **đề xuất, chờ Legal** | — | Legal (`OQ-007`) | | Xác thực danh tính người yêu cầu xoá (chống giả mạo yêu cầu xoá tài khoản người khác) | Ý tưởng tham khảo P1 (`docs/08 §8.2.4`), chưa thiết kế cụ thể cho P2 | 🔴 Chưa thiết kế | — | Legal + Tech Lead (mới, ngoài phạm vi US-002/003) | ### 8.3 NĐ52/85 (thông báo website TMĐT marketplace) *Chủ yếu là nghĩa vụ pháp lý/hành chính (đăng ký với Bộ Công Thương), không phải control kỹ thuật thuộc `SEC`. Yêu cầu kỹ thuật liên quan (hiển thị thông tin đăng ký ở footer) thuộc tầng UI/FE, ngoài phạm vi tài liệu này.* --- ## 9. Phụ thuộc & chuỗi cung ứng | | Quyết định | |---|---| | Quét lỗ hổng thư viện (SCA) | Trivy/Snyk/Dependabot trong CI/CD — đề xuất chặn build nếu phát hiện CVE mức **Critical** chưa có bản vá sau **7 ngày**, mức **High** sau **30 ngày** (đề xuất SA, chưa Tech Lead xác nhận) | | Quét ảnh container | Trivy image scan trước khi push lên ECR — cùng ngưỡng chặn như trên | | Chính sách vá lỗ hổng nghiêm trọng | Critical: ≤7 ngày · High: ≤30 ngày · Medium/Low: theo chu kỳ release thường | | Ai duyệt thư viện mới | Tech Lead (theo `decision-radar.md §5` — "Công cụ, thư viện" thuộc Tech Lead, SA chỉ phủ quyết nếu chạm `QAS`) | | Pentest năm + ASV quý | Xem §8.1 — chi phí chưa có báo giá (`OQ-017`, đã mở ở `TCO`) | --- ## 10. Giả định & Ngoài phạm vi **Giả định** *(tiếp số toàn dự án — `ASM-01…38` đã dùng, bắt đầu `ASM-39`)*: | ID | Giả định | Cách xác minh | Nếu sai | |---|---|---|---| | `ASM-39` | VNPay/Momo hỗ trợ tích hợp dạng redirect thuần (không bắt buộc iframe/SDK truyền dữ liệu thẻ qua domain sàn), đủ điều kiện giữ SAQ A | Tech Lead xác nhận khi có tài liệu/sandbox thật (`OQ-048`, `ARISK-03`) | Nếu sai: phạm vi tuân thủ PCI-DSS phải nâng lên (SAQ A-EP hoặc cao hơn), ảnh hưởng trực tiếp `ASR-002`/`ADR-002`/chi phí `TCO` — cần rà lại toàn bộ `SEC §8.1` | | `ASM-40` | Chưa có đủ traffic thật để hiệu chỉnh ngưỡng rate-limit (§5.3) — ba con số (30/10/10) là ước lượng dựa trên hành vi UI thông thường, không phải đo | Đo traffic thật 4-6 tuần đầu soft-launch, điều chỉnh lại | Nếu traffic thật khác biệt lớn (VD nhiều khách dùng chung IP NAT hơn dự kiến): cần tách ngưỡng theo `session_id` thuần, giảm phụ thuộc IP | | `ASM-41` | Đề xuất PA-3 (service JWT) cho service-to-service authn (§2.4) không làm tăng đáng kể latency đường găng checkout (`QAS-002`) | Đo lại `QAS-002` sau khi có thiết kế cụ thể + `POC` nếu Tech Lead chấp nhận hướng này | Nếu tăng latency đáng kể: cần xét lại PA-2 (mTLS, chấp nhận thêm hạ tầng) hoặc thiết kế cache token phía service gọi | **Ngoài phạm vi:** - Threat model chi tiết cho các `CMP` ngoài "chi tiết nhất" (Seller Mgmt ngoài whitelist PII, Commission & Payout, Promotion & Loyalty ngoài `IF-021`, Review, Notification) — chỉ có ở mức ranh giới tin cậy (§1), chưa đào sâu STRIDE riêng. Sẽ bổ sung khi module tương ứng tới lượt thiết kế chi tiết. - Cơ chế chữ ký/HMAC cụ thể của VNPay/Momo/GHN/GHTK — **không bịa**, chờ tài liệu/sandbox đối tác thật (`ARISK-03/04`, `OQ-049`). - Hạ tầng cụ thể cho VPN/IP allowlist Admin, mã hoá in-transit ElastiCache, cấu hình IAM DB role chi tiết theo schema — thuộc hoạt động `inf` (hoạt động 7, chưa chạy). - Endpoint đọc `audit_log` tập trung, DPIA (Data Protection Impact Assessment) — ngoài phạm vi US-002/003, ghi nhận là việc cần làm trước go-live (tham khảo `docs/08 §8.4`). - Viết `ADR` chính thức cho service-to-service authn (§2.4) — chỉ đề xuất và ước lượng radar ở đây, việc viết `ADR` thuộc hoạt động `adr` kế tiếp (ngoài phạm vi hoạt động `sec` được giao). --- ## 11. Open Questions *Tiếp số sổ SA (`00-index/OQ_e-commerce.md` đang ở `OQ-047`) — bắt đầu `OQ-048`.* | ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | Hệ quả nếu trả lời ngược | |---|---|---|---|---|---| | `OQ-048` | VNPay/Momo có hỗ trợ tích hợp dạng redirect thuần (không iframe/SDK nhập thẻ trên domain sàn) không — điều kiện để giữ phạm vi PCI-DSS SAQ A (`ASM-39`)? | Tech Lead + Security (khi có người) | 2026-09-15 | `SEC §8.1`; giả định nền của `ASR-002`/`ADR-002` | Nếu không hỗ trợ redirect thuần: phạm vi tuân thủ PCI-DSS phải nâng cấp, tăng chi phí audit/kiểm toán và có thể cần thiết kế lại luồng khởi tạo thanh toán | | `OQ-049` | Cơ chế xác thực chữ ký/HMAC webhook cụ thể của VNPay, Momo, GHN, GHTK là gì (thuật toán, header, cách tính chữ ký)? | Tech Lead (khi có tài liệu đối tác) | 2026-09-15 | `THR-17`/`THR-22`; kiểm chứng `ADR-004` thật | Không có tài liệu: threat model webhook chỉ dừng ở mức nguyên tắc chung ("phải xác thực"), không kiểm chứng được cho tới khi có sandbox — rủi ro triển khai sai cơ chế lúc code | | `OQ-050` | Chấp nhận đề xuất PA-3 (service JWT ngắn hạn ký bởi Identity & Access) cho service-to-service authn giữa Nhóm Giao dịch ↔ Nhóm Hỗ trợ ↔ Payment không, hay chọn PA-2 (mTLS/App Mesh, cần thêm hạ tầng)? | Tech Lead + Security + Ops/SRE | 2026-09-15 | `ADR` mới ở hoạt động `adr` kế tiếp; thiết kế `inf` cho TB3/TB4 | Chọn PA-3: rủi ro còn lại là chưa đạt mTLS full zero-trust, nhưng không cần hạ tầng mới ngay. Chọn PA-2: cần quyết định lại ràng buộc "không thêm hạ tầng mới" đã ghi ở `SAD §7` v1.2, tăng thời gian/chi phí triển khai | | `OQ-051` | Xác nhận số cụ thể: TTL access token (đề xuất 15 phút), TTL refresh token (đề xuất 14 ngày), cơ chế thu hồi tức thời (đề xuất denylist Redis theo `jti`), tần suất xoay khoá ký JWT (đề xuất 90 ngày) | Tech Lead | 2026-09-15 | Thiết kế `CMP-02` (Identity & Access) khi tới lượt module đó; toàn bộ luồng authn Customer/Seller/Admin | Số quá ngắn (VD TTL 5 phút): tăng tần suất refresh, tăng tải Identity & Access. Số quá dài (VD TTL 60 phút không denylist): cửa sổ lợi dụng token bị đánh cắp dài hơn | | `OQ-052` | Xác nhận ngưỡng account lockout theo vai trò (đề xuất: customer/seller 5 lần sai/15 phút; admin 3 lần sai/30 phút) và rate-limit login theo IP (đề xuất 10 request/phút) | Tech Lead + Security | 2026-09-15 | `THR-28/31`; thiết kế `CMP-02` | Ngưỡng quá chặt: tăng khiếu nại khách bị khoá oan (đặc biệt IP NAT dùng chung). Ngưỡng quá lỏng: tăng rủi ro brute-force thành công | | `OQ-053` | Ba trường whitelist chia sẻ cho seller (`recipient_name`/`phone`/`address_line`, `ADR-008` PA-2) hiển thị đầy đủ hay che một phần (VD số điện thoại che 3-4 số giữa)? | Security/Legal (khi có người) + PO | 2026-09-15 | `DAT §5.2`; UI hiển thị đơn hàng cho Seller (ngoài phạm vi US-002/003) | Hiển thị đầy đủ: seller đủ thông tin giao hàng nhưng tăng bề mặt rủi ro nếu tài khoản seller bị lộ. Che một phần: giảm rủi ro nhưng có thể gây khó khăn thao tác giao hàng thực tế (VD shipper cần gọi điện xác nhận) | **Cập nhật cho `OQ` đã mở:** - **`OQ-007`** — SEC bổ sung: toàn bộ §5, §8.2 của tài liệu này là **đề xuất chờ phủ quyết**; không coi bất kỳ phân loại/whitelist/mã hoá nào ở đây là đã "Security xác nhận". **Giữ nguyên mở.** - **`OQ-023`** — SEC trả lời bằng đề xuất số cụ thể ở §5.3 (30 req/phút Guest cart, kèm hệ quả cả hai chiều) — **không tự quyết thay Security**, `OQ-023` **giữ nguyên mở**, chờ Security xác nhận hoặc điều chỉnh. - **`OQ-024`** (MFA Admin) — SEC xác nhận lại hướng TẠM TOTP app (`ASM-20`, `DEC-14`) và bổ sung chi tiết backup code (§2 bảng, chưa thiết kế đầy đủ) — **giữ nguyên mở**, chờ Security thật. **Nhắc:** cộng với các `OQ` còn mở ảnh hưởng trực tiếp `SEC` — `OQ-007` (PII/residency, chặn phần lớn §5/§8.2), `OQ-017` (báo giá pentest/ASV, chặn §8.1/§9), `ARISK-03/04` (sandbox đối tác, chặn kiểm chứng `THR-17/18/22`) — xem sổ đầy đủ `00-index/OQ_e-commerce.md`. **Nhắc AG2:** cần **Tech Lead + Security + Ops/SRE ký** — còn thiếu `INF` (hoạt động 7) và toàn bộ `ADR` liên quan `SEC` (`ADR-002/004/007/008` vẫn `Proposed`; `ADR` service-to-service authn §2.4 chưa viết). --- ## Tự chấm ### ① Bảng tự chấm Gate AG2 *(`workflow.md §2` — chỉ dòng liên quan tới `SEC`, tự chấm sớm)* | # | Tiêu chí | ☐/✅ | Ghi chú | |---|---|---|---| | — | `ASR`/`QAS`/`SAD`/`ICD`/`DAT`/`FAIL` | ✅ *(đã đạt ở các hoạt động trước)* | Không lặp lại | | — | `ADR-nnn` tồn tại cho mọi quyết định đạt ngưỡng radar | 🟡 Một phần | 13 `ADR` đã viết (bao gồm `ADR-002/004/007/008/011` liên quan bảo mật); `SEC` phát hiện **1 quyết định mới đạt ngưỡng ADR** chưa viết — service-to-service authn (§2.4, radar ~5), ghi `OQ-050` | | — | `INF` | ☐ | Chưa tới — hoạt động 7 | | 1 | `SEC` — có threat model STRIDE cho luồng nhạy cảm; mô hình authn/authz đã chốt; **Security ký** | ☐ | Threat model STRIDE đủ 8 ranh giới, 31 `THR` (§4); mô hình authn/authz đã **đề xuất đầy đủ** (§2, §3) nhưng **chưa chốt** ở nhiều điểm (`OQ-050/051/052/053`) và **Security chưa ký** (`OQ-007`, không có người) — đây là điều kiện chặn cứng nhất của AG2 theo `SKILL.md` ("Security có quyền phủ quyết AG2") | | — | `sa-conformance` báo coverage `ASR → ADR/CMP` ≥ 100% | *(không đổi bởi `SEC`)* | `SEC` không tạo `CMP`/`ASR` mới; có đề xuất 1 `ADR` mới (service-authn) chưa viết | **Kết luận tự chấm (riêng phần `SEC`):** Hoạt động `sec` hoàn tất đúng phạm vi được giao — threat model STRIDE đủ 8 ranh giới tin cậy yêu cầu (31 `THR`), mô hình authn/authz đầy đủ cho Guest/ Customer/Seller/Admin + phát hiện khoảng trống service-to-service authn (mới, `OQ-050`), map đủ 2/2 `ROLE-nn` của `RBAC_CartCheckout`, PCI-DSS/NĐ13/2023 rà theo yêu cầu (mọi kết luận PII đánh dấu "đề xuất chờ Legal"), audit log + secret management + chuỗi cung ứng đã chốt trường/chính sách đề xuất. **AG2 còn xa** vì (a) `INF` (hoạt động 7) chưa chạy, (b) Security **chưa có người** (`OQ-007`) nên **không ai có quyền phủ quyết/ký** — đây là điều kiện chặn nghiêm trọng nhất, đúng cảnh báo của `GUIDE.md`: "phát hiện muộn nhất và đau nhất luôn đến từ đây." ### ② Checklist D1–D12 *(`design-rules.md`)* | # | Mục | ☐/✅ | Ghi chú | |---|---|---|---| | D1 | Một ADR một quyết định | N/A | `SEC` không viết `ADR` mới ở lượt này — chỉ đề xuất 1 `ADR` ứng viên (service-authn, §2.4) cho hoạt động `adr` kế tiếp | | D2 | Không NFR định tính | ✅ | Mọi ngưỡng (rate-limit, TTL token, lockout) đều có con số hoặc đánh dấu rõ "chưa chốt" kèm `OQ` — không có mục nào ghi "bảo mật tốt" chung chung | | D3 | Nêu phương án bị loại + lý do | ✅ | §2.4 (3 phương án service-authn, PA-1/PA-2 bị loại có lý do gắn ràng buộc `SAD §7`) | | D4 | Sơ đồ khai báo mức + legend | ✅ | §1 khai báo rõ "ranh giới tin cậy" (`flowchart LR` theo `D4`), có legend | | D5 | Interface có chủ/contract | N/A | Đã xử lý ở `ICD` (hoạt động 4); `SEC` chỉ bổ sung khía cạnh xác thực/authz cho các `IF` đã có | | D6 | Phụ thuộc ngoài process có timeout/retry | N/A | Đã xử lý ở `FAIL` (hoạt động 8); `SEC` chỉ bổ sung khía cạnh threat/xác thực | | D7 | Một chủ sở hữu dữ liệu | N/A | Đã xử lý ở `DAT` (hoạt động 5); `SEC` chỉ tham chiếu khi thiết kế IAM theo schema (§4.7) | | D8 | Ràng buộc có FIT hoặc nhãn khuyến nghị | 🟡 Một phần | Đề xuất `FIT-29` (secret scan), `FIT-30` (service-authn test, chờ `OQ-050`), `FIT-31` (webhook signature test, chặn bởi `ARISK-03/04`), `FIT-32` (audit completeness), `FIT-33` (TLS/HSTS config test) — ứng viên GĐ3, chưa viết thật; các threat chưa có biện pháp đủ (`THR-09/13/17/22`) đánh dấu rõ "chưa kiểm chứng được", không giả vờ đã có `FIT` | | D9 | Con số hạ tầng quy ra tiền + nguồn | N/A | `SEC` không thêm con số hạ tầng mới (Secrets Manager/WAF đã có trong `TCO`/`SAD` từ trước) | | D10 | Không quyết định thay người có thẩm quyền | ✅ | Mọi kết luận PII/residency đánh dấu "đề xuất chờ Legal/Security" (§5, §8.2); rate-limit (§5.3), account lockout (§2.3), service-authn (§2.4) đều trình phương án kèm hệ quả hai chiều, không tự quyết; §4.9 để trống vì không tự chấp nhận rủi ro thay Security | | D11 | Có mục "Ngoài phạm vi" + `ASM-nn` | ✅ | §10 đầy đủ — `ASM-39…41` mới, có cách xác minh/hệ quả | | D12 | Câu quy định thẩm quyền sơ đồ vs văn bản | ✅ | Có ngay sau Change Log | ### ③ Bảng đối chiếu với bộ BA — `RBAC` ↔ `SEC` | `RBAC_CartCheckout` (BA) | Nội dung | `SEC` tương ứng | Khớp? | Hành động | |---|---|---|---|---| | §1 (2 vai trò: Guest, Customer) | Ma trận vai trò | §3.1 (map đủ `ROLE-01/02`) | ✅ | Không lệch — 2/2 `ROLE-nn` có dòng map, đúng yêu cầu "mỗi `ROLE-nn` phải có đúng một dòng, thiếu ⇒ chặn AG2" | | §2 (không ai xem giỏ/đơn người khác) | Ranh giới ownership | §3 (fail-closed), `THR-07` | ✅ | Khớp — `ASR-007`/`ADR-007` đã hiện thực hoá đúng | | §3 (SoD không áp dụng) | Tự phục vụ, không có duyệt kép | §3.2 | ✅ | Kế thừa nguyên trạng kết luận của BA, không lệch | | §4 (mức che PII cho seller — chưa chốt) | Whitelist chưa quyết định mức che | §5.2, `OQ-053` (mới) | 🟡 Một phần | `SEC` xác nhận whitelist 3 trường (`ADR-008`) nhưng **mức che cụ thể vẫn chưa chốt** như BA đã ghi nhận — **BA không cần sửa `RBAC`**, câu hỏi này tiếp tục do Security/Legal quyết định khi có người | | §5 (lưu vết — "chưa chốt thời hạn") | Audit log cho `Order`/`Payment` | §7 (10 năm, append-only) | 🟡 Một phần | `SEC` đề xuất retention cụ thể (10 năm) — **BA có thể cập nhật `RBAC_CartCheckout §5`** tham chiếu `SEC §7` khi retention được Security/Tech Lead xác nhận thật | | §6 (hành vi khi không đủ quyền) | 403/không hiển thị dữ liệu | §3 (fail-closed 503 cho lỗi kỹ thuật, phân biệt với 403 thật) | ✅ Bổ sung | `SEC` làm rõ thêm trường hợp BA chưa phân biệt (lỗi kỹ thuật khi kiểm tra ownership ≠ "không có quyền" thật) — **BA nên bổ sung `AC` mới cho `E-CART-0007`** (đã ghi ở `FAIL`, nhắc lại ở đây) | | §8 `OQ-012` (Guest OTP đơn giá trị cao) | Chưa chốt | *(ngoài phạm vi `SEC` — thuộc `BR-CART-03`, quyết định PO)* | ➖ N/A | Không hành động — đây là quyết định nghiệp vụ, không phải kiến trúc bảo mật | | §8 `OQ-015` (chống lạm dụng Guest checkout) | Chưa chốt | §5.3 (đề xuất rate-limit checkout 10/phút) | ✅ Trả lời | `SEC` đã đề xuất số cụ thể — **BA có thể đóng `OQ-015` trong sổ BA**, tham chiếu `SEC §5.3`, với điều kiện Security xác nhận số cuối cùng | | §8 `OQ-016` (mức che PII cho seller) | Chưa chốt | Trùng với `RBAC §4` ở trên | 🟡 Một phần | Cùng trạng thái — chờ Security/Legal, xem `OQ-053` (SA) | ### ④ Danh sách `OQ` mở kèm người phải trả lời, chặn gì Xem §11 (`OQ-048…053` mới) cộng cập nhật `OQ-007/023/024`. Ba câu hỏi quan trọng nhất cho AG2: **`OQ-007`** (chưa có người Security/Legal — chặn toàn bộ hiệu lực phủ quyết của `SEC`), **`OQ-050`** (service-to-service authn — khoảng trống kiến trúc mới phát hiện, ảnh hưởng TB3/TB4 nơi PII và tiền đi qua), **`OQ-048`/`OQ-049`** (chưa có tài liệu/sandbox đối tác thanh toán/vận chuyển thật — chặn kiểm chứng phần lớn threat model TB5/TB6). Sổ đầy đủ: `00-index/OQ_e-commerce.md`. **Nhắc:** AG2 cần **Tech Lead + Security + Ops/SRE ký** — còn thiếu `INF` (hoạt động 7) và **chưa có người Security** để ký bất kỳ phần nào của `SEC`. Đây là rủi ro tiến độ nghiêm trọng nhất của toàn GĐ2: theo `GUIDE.md`, "Bước `sec` cần một người thật từ Security ngồi cùng" — điều này **chưa xảy ra** trong suốt hoạt động `sec` vừa chạy, toàn bộ nội dung là công việc chuẩn bị một chiều của SA, chờ người đó xuất hiện.