Phân loại dữ liệu — GIW POC Identity Platform
Trạng thái: POC · Ngày: 21/09/2026 Căn cứ pháp lý: Luật Bảo vệ dữ liệu cá nhân 91/2025/QH15 · Nghị định 356/2025/NĐ-CP
1. Các lớp dữ liệu
| Lớp | Định nghĩa | Cách xử lý |
|---|---|---|
PUBLIC |
Công bố được | Không cần kiểm soát |
INTERNAL |
Dữ liệu vận hành, không phải dữ liệu cá nhân | Kiểm soát truy cập, được ghi log |
PERSONAL |
Dữ liệu cá nhân cơ bản | Cần sự đồng ý, tối thiểu hoá, giới hạn thời gian lưu; chỉ ghi log dưới dạng định danh |
SENSITIVE |
Dữ liệu cá nhân nhạy cảm (Điều 3) | Đồng ý rõ ràng, mã hoá trên đường truyền, không bao giờ ghi log, lưu trữ nghiêm ngặt |
SECRET |
Thông tin xác thực hệ thống | Không ghi log, không nằm trong repository, phải xoay vòng được |
2. Sổ đăng ký trường dữ liệu
| Trường | Lớp | Nguồn | Mục đích | Lưu ở đâu | Thời gian lưu | Che giấu | Ghi log |
|---|---|---|---|---|---|---|---|
employeeId |
PERSONAL |
Người dùng nhập trên form nhân viên | Khoá tra cứu ở HR | Không đâu cả. Không ghi vào Keycloak; chỉ giữ trong bộ nhớ một request | Vòng đời request | Không che trong log — xem ghi chú | Được phép (chỉ id) |
citizenId (CCCD) |
SENSITIVE |
Người dùng nhập trên form nhân viên | Xác minh một lần với HR | Không đâu cả. Không trong Keycloak, không trong service nào, không trong cache nào | Chỉ vòng đời request | Hiển thị dạng type=password; không bao giờ trả lại |
CẤM — có test tự động cưỡng chế |
memberRef |
INTERNAL |
Response của Loyalty API | Truy vết một entitlement về nguồn loyalty | Kho entitlement (trong bộ nhớ, POC); không nằm trong token | Theo TTL của entitlement | Không cần | Được phép |
memberTier |
INTERNAL |
Response của Loyalty API | Đầu vào bảng quyết định | Không lưu — tra lại mỗi lần đăng nhập | Vòng đời request | Không cần | Được phép |
email (gửi sang loyalty) |
PERSONAL |
Claim trong token, gửi làm khoá tra cứu | Tìm hội viên đã có | Không đâu cả — loyalty service so sánh rồi bỏ | Vòng đời request | Cả hai bên đều không ghi log | CẤM trong log của loyalty |
employeeRef |
INTERNAL |
Response của HR API | Khoá liên kết ổn định, không định danh người | User attribute employee_ref của Keycloak; claim trong access token |
Theo vòng đời bản ghi user | Không cần | Được phép |
company |
INTERNAL |
Response của HR API | Điều kiện hưởng entitlement | User attribute của Keycloak; claim trong token | Theo vòng đời bản ghi user | Không cần | Được phép |
employeeStatus / active |
INTERNAL |
Response của HR API | Cổng chặn xác thực | Không lưu — tra lại mỗi lần đăng nhập | Vòng đời request | — | Được phép |
wifiEligible |
INTERNAL |
Response của HR API | Cổng chặn xác thực | Không lưu | Vòng đời request | — | Được phép |
email |
PERSONAL |
Tự đăng ký | Định danh tài khoản, đặt lại mật khẩu | Bản ghi user của Keycloak | Tới khi xoá tài khoản | Che trong log nếu buộc phải ghi | Nên tránh; dùng sub |
phone |
PERSONAL |
POC này không thu thập | — | — | — | — | — |
sub của Keycloak |
PERSONAL (định danh giả) |
Keycloak | Subject id ổn định xuyên các service | Keycloak; kho entitlement; kho session | Theo vòng đời bản ghi user | Không | Được phép — đây mới là khoá log đúng |
sessionId |
INTERNAL |
Session Service | Tay cầm của phiên truy cập | Kho session (trong bộ nhớ, POC) | Tới khi thu hồi/hết hạn | Không | Được phép |
entitlementId |
INTERNAL |
Entitlement Service | Tay cầm của quyết định, dấu vết audit | Kho entitlement (trong bộ nhớ, POC) | Theo TTL của entitlement | Không | Được phép |
deviceRef |
INTERNAL |
Tay cầm mờ do portal sinh | Đối chiếu thiết bị trong một phiên | Kho session | Vòng đời phiên | Không | Được phép |
correlationId |
INTERNAL |
Sinh theo dạng corr-<uuid4> |
Truy vết xuyên service | Log của mọi service | Theo thời gian lưu log | Không | Được phép — đó chính là nhiệm vụ của nó |
access_token |
SECRET |
Keycloak | Credential dạng bearer | Bản đồ phiên phía server của portal; trình duyệt chỉ giữ cookie mờ sid |
900 s | Không bao giờ in ra | CẤM |
refresh_token |
SECRET |
Keycloak | Gia hạn truy cập | Chỉ trong bản đồ phiên phía server của portal | SSO idle 1800 s | Không bao giờ in ra | CẤM |
id_token |
SECRET |
Keycloak | Kiểm nonce, gợi ý khi logout | Bản đồ phiên phía server của portal | Vòng đời phiên | Không bao giờ in ra | CẤM |
HR_API_KEY |
SECRET |
.env |
Xác thực giữa các service | .env (đã git-ignore) và biến môi trường container |
Xoay vòng khi bị lộ | — | CẤM |
SESSION_API_KEY |
SECRET |
.env |
Xác thực giữa các service | .env (đã git-ignore) và biến môi trường container |
Xoay vòng khi bị lộ | — | CẤM |
KC_ADMIN_PASSWORD |
SECRET |
.env |
Chỉ dùng cho bootstrap | .env và biến môi trường container |
Xoay vòng trước khi lên bất kỳ môi trường dùng chung nào | — | CẤM |
PKCE code_verifier |
SECRET |
Portal | Ràng buộc authorization code | Bộ nhớ portal, dùng một lần | Một request | — | CẤM |
OIDC state / nonce |
INTERNAL |
Portal | Chống CSRF và replay | Bộ nhớ portal, dùng một lần | Một request | — | Được phép |
Ghi chú về việc log employeeId. Nó là dữ liệu cá nhân và nó có được ghi log (log truy cập HR, log quyết định của authenticator). Đây là đánh đổi có chủ đích: không có nó thì một lần xác minh thất bại không thể điều tra được. Đó là mức tối thiểu để hệ thống còn hỗ trợ được. citizenId thì không, và không được ghi log.
3. Vòng đời đầy đủ của CCCD
ô nhập trên trình duyệt (type=password, autocomplete=off)
│ HTTPS ở production; HTTP thuần trên localhost cho POC
▼
Custom authenticator của Keycloak
│ chỉ là biến cục bộ — không field, không session note, không user attribute
▼
Body request gửi HR Verification API
│ so sánh thời gian hằng số với các bản ghi tổng hợp
▼
bị huỷ
Những chỗ nó có thể rò, và cái gì chặn lại:
| Đường rò | Biện pháp |
|---|---|
| Dòng log trong authenticator | Mọi lệnh log chỉ nhận corr + employeeId; lớp client có ghi rõ điều này và không bao giờ nội suy body vào |
| Thông báo exception vọng lại request | HrVerificationClient bắt lỗi và chỉ log e.getClass().getSimpleName(), không bao giờ e.getMessage() |
| User attribute của Keycloak | Authenticator ghi đúng bốn attribute có tên; một comment đánh dấu việc bỏ sót là cố ý |
| Access token | Scope giw-identity ánh xạ bốn attribute; CCCD không nằm trong đó và cũng không được lưu để mà ánh xạ |
| Response của HR API | Response dựng từ bản ghi đã khớp, không bao giờ vọng lại từ request — có test khẳng định |
| Body lỗi | Mô hình lỗi chuẩn không có trường nào cho nó; message là chuỗi cố định |
| Event log của Keycloak | Event chỉ mang giw_correlation_id và giw_employee_ref |
| Tự điền / lịch sử trình duyệt | Ô nhập là type=password kèm autocomplete="off"; không trả lại giá trị khi thử thất bại |
Hai test tự động cưỡng chế điều này và đánh trượt cả bộ khi có hồi quy:
- "no CCCD value appears in any container log" — quét log cả năm container tìm mọi CCCD dùng trong test.
- "no CCCD is persisted on the Keycloak user record" — đọc mọi user nhân viên đã tạo qua Admin API và từ chối cả giá trị gốc lẫn mọi tên attribute khớp
/citizen|cccd|national/i.
4. Dữ liệu test
Mọi bản ghi HR trong mock-hr-api/src/employees.json đều là dữ liệu tổng hợp. Không người thật, không hồ sơ nhân viên thật, không số căn cước thật. Tệp này có một trường _comment ghi rõ như vậy.
5. Bên kiểm soát / Bên xử lý — chưa chốt
| Câu hỏi | Trạng thái |
|---|---|
| Ai là Bên kiểm soát dữ liệu đối với danh tính hành khách — Galaxy Holdings hay Vietjet? | TBC (quyết định D7) |
| Ai là Bên kiểm soát đối với dữ liệu xác minh nhân viên? | TBC — nhiều khả năng là pháp nhân sử dụng lao động, không phải Galaxy |
| Galaxy có phải Bên xử lý khi nó gọi HR không? | TBC |
| Có bắt buộc làm DPIA trước khi POC chạm vào dữ liệu HR thật không? | Cứ giả định là có. POC này dùng dữ liệu tổng hợp chính là để không cần tới nó. |
POC này không được trỏ vào một hệ thống HR thật cho tới khi D7 được quyết.
6. Khoảng trống so với production
| Khoảng trống | Tác động |
|---|---|
| Kho entitlement và session nằm trong bộ nhớ | Không có chính sách lưu trữ, không có khả năng xoá. Chặn mọi lượt chạy với dữ liệu thật. |
| Không mã hoá khi lưu | Volume Postgres của Keycloak không mã hoá. |
| Không thu thập sự đồng ý | POC không ghi nhận bằng chứng đồng ý nào. Luật 91/2025 yêu cầu phải có cho đường CCCD. |
| Không có endpoint cho quyền truy cập / xoá dữ liệu của chủ thể | Production bắt buộc phải có. |
| HTTP thuần | Chỉ chấp nhận được trên localhost. |