Mở đầu — vì sao bài này quan trọng
Hãy hình dung tình huống này: một ngân hàng số tại Việt Nam bị rò rỉ một file backup database chứa thông tin 2 triệu khách hàng. Báo chí đưa tin, cổ phiếu rớt giá, khách hàng hoảng loạn. Nhưng rồi đội kỹ thuật công bố một chi tiết quan trọng: toàn bộ dữ liệu trong file đó đã được mã hóa AES-256, và kẻ tấn công không có khóa giải mã. Khủng hoảng từ "thảm họa" tụt xuống thành "sự cố cần khắc phục". Sự khác biệt một trời một vực đó chính là giá trị của encryption (mã hóa).
Là một Technical BA, bạn không cần tự tay viết thuật toán mã hóa — đó là việc của developer và security engineer. Nhưng bạn là người viết spec quyết định dữ liệu nào phải được mã hóa, mã hóa ở trạng thái nào, và ai được phép giữ khóa. Nếu bạn bỏ sót một dòng yêu cầu "số thẻ tín dụng phải mã hóa khi lưu trữ", developer có thể vô tư lưu plaintext, và doanh nghiệp lãnh án phạt PCI-DSS hàng trăm nghìn USD. Ngược lại, nếu bạn yêu cầu mã hóa tất tần tật mọi thứ một cách máy móc, hệ thống sẽ chậm, đắt và khó vận hành.
Bài này dạy bạn một khung tư duy cực kỳ thực dụng: ba trạng thái của dữ liệu — at rest (lưu trữ), in transit (truyền tải), và in use (đang xử lý). Hiểu rõ ba trạng thái này, bạn sẽ biết chính xác cần đặt câu hỏi gì cho kiến trúc sư, viết yêu cầu gì vào spec, và đánh giá rủi ro ở đâu. Đây là kiến thức mà mọi Technical BA làm trong ngành tài chính, y tế, fintech hay e-commerce đều bắt buộc phải nắm.
Khái niệm cốt lõi
Encryption về bản chất là quá trình biến dữ liệu đọc được (plaintext) thành dữ liệu không đọc được (ciphertext) bằng một thuật toán và một khóa (key). Chỉ người nắm khóa đúng mới giải mã ngược lại được. Điểm mấu chốt bạn cần nhớ: độ an toàn nằm ở việc quản lý khóa, không phải ở việc giấu thuật toán. Các thuật toán như AES, RSA đều công khai; cái phải giữ bí mật là khóa.
Dữ liệu trong vòng đời của nó luôn ở một trong ba trạng thái, và mỗi trạng thái cần một cơ chế bảo vệ khác nhau.
1. At rest — Dữ liệu khi lưu trữ
Đây là dữ liệu nằm yên trên ổ cứng, trong database, trong file backup, trên USB, hay trong các bucket lưu trữ đám mây như Amazon S3. Mối đe dọa điển hình: ai đó lấy được ổ cứng vật lý, trộm file backup, hoặc truy cập trái phép vào storage.
Có hai cấp độ mã hóa at rest mà bạn cần phân biệt:
- Disk-level / Full Disk Encryption (FDE): mã hóa toàn bộ ổ đĩa. Ví dụ AWS EBS encryption, BitLocker, LUKS trên Linux. Cấp này bảo vệ khi ai đó trộm ổ cứng vật lý, nhưng khi hệ điều hành đã mở khóa và đang chạy thì dữ liệu hiện ra bình thường với mọi tiến trình.
- Database-level — Transparent Data Encryption (TDE): database tự mã hóa các file dữ liệu của nó. Oracle, SQL Server, PostgreSQL (qua extension) đều hỗ trợ. "Transparent" nghĩa là ứng dụng không cần đổi code — database lo việc mã hóa/giải mã ngầm.
- Application-level / Column-level encryption: ứng dụng mã hóa từng trường nhạy cảm trước khi ghi xuống DB. Ví dụ chỉ mã hóa cột
card_number,cccd,salary. Cấp này bảo vệ tốt nhất vì ngay cả DBA cũng không đọc được, nhưng phức tạp hơn (khó search, khó index).
2. In transit — Dữ liệu khi truyền tải
Đây là dữ liệu đang di chuyển qua mạng: từ trình duyệt đến server, giữa hai microservice, từ app đến API, từ hệ thống bạn đến hệ thống đối tác. Mối đe dọa: kẻ tấn công "nghe lén" đường truyền (man-in-the-middle attack), bắt gói tin trên Wi-Fi công cộng, hoặc chặn lưu lượng giữa các trung tâm dữ liệu.
Cơ chế bảo vệ chuẩn là TLS (Transport Layer Security) — chính là cái "khóa xanh" và "https" bạn thấy trên trình duyệt. Quy tắc vàng cho spec hiện nay: bắt buộc TLS 1.2 trở lên, ưu tiên TLS 1.3; cấm tiệt SSL và TLS 1.0/1.1 vì đã có lỗ hổng. TLS làm hai việc: mã hóa nội dung và xác thực danh tính server qua chứng chỉ (certificate).
Một khái niệm bạn nên đưa vào spec cho hệ thống nhạy cảm là mTLS (mutual TLS) — cả client lẫn server đều phải trình chứng chỉ để xác thực lẫn nhau, thường dùng giữa các dịch vụ nội bộ hoặc khi tích hợp với ngân hàng/đối tác.
3. In use — Dữ liệu khi đang xử lý
Đây là trạng thái khó nhất và mới nhất. Khi CPU cần tính toán trên dữ liệu, nó phải giải mã ra plaintext nạp vào RAM. Tại khoảnh khắc đó, dữ liệu "trần trụi" — một kẻ tấn công có quyền truy cập memory dump, hoặc một insider có quyền admin, vẫn đọc được. At rest và in transit không bảo vệ được trạng thái này.
Các công nghệ bảo vệ in use còn khá mới:
- Confidential Computing / Trusted Execution Environment (TEE): vùng nhớ được CPU bảo vệ và cô lập (Intel SGX, AMD SEV, AWS Nitro Enclaves). Dữ liệu giải mã chỉ tồn tại bên trong "enclave" mà ngay cả OS hay hypervisor cũng không nhìn vào được.
- Homomorphic encryption: cho phép tính toán trực tiếp trên ciphertext mà không cần giải mã. Rất mạnh về lý thuyết nhưng còn chậm, hiện chủ yếu dùng cho các bài toán đặc thù.
Quản lý khóa — linh hồn của mọi giải pháp
Mã hóa mạnh đến đâu cũng vô nghĩa nếu khóa bị lộ hoặc bị mất. Vì vậy spec phải luôn nói về Key Management. Trong thực tế người ta dùng KMS (Key Management Service) như AWS KMS, Azure Key Vault, Google Cloud KMS, hoặc HSM (Hardware Security Module) cho mức bảo mật cao nhất. Hai nguyên tắc bạn cần ghi nhớ: không bao giờ hard-code khóa trong source code, và phải có quy trình xoay khóa định kỳ (key rotation).
Tình huống thực tế
Tình huống 1 — Fintech ví điện tử và sự cố thiếu mã hóa cột
Một startup ví điện tử tại TP.HCM (gọi là "PayViet") triển khai tính năng liên kết thẻ ngân hàng. Đội dev vội ra mắt nên lưu số thẻ và ngày hết hạn dưới dạng plaintext trong PostgreSQL, với lý do "database đã bật TDE rồi, an toàn rồi". Sáu tháng sau, một nhân viên DevOps cũ rời công ty nhưng vẫn còn quyền truy cập read-only vào database production. Người này export được toàn bộ bảng thẻ.
Vấn đề ở đây rất tinh tế: TDE chỉ bảo vệ at rest ở mức file đĩa. Khi database đang chạy và bạn có quyền query hợp lệ, TDE giải mã trong suốt và trả về plaintext. TDE không chống được insider có quyền đăng nhập DB. Đáng lẽ Technical BA phải viết spec yêu cầu mã hóa ở mức cột (column-level/application-level encryption) cho số thẻ, kết hợp tokenization — tức là số thẻ thật được thay bằng token, và chỉ payment gateway đạt chuẩn PCI-DSS mới giữ số thật.
Bài học: Đừng nhầm "đã bật mã hóa at rest" là "dữ liệu đã an toàn tuyệt đối". BA phải hỏi rõ: mã hóa ở cấp nào, ai có khóa, ai có thể đọc plaintext. Với dữ liệu thẻ thanh toán, mức đĩa và TDE là không đủ.
Tình huống 2 — Tích hợp ngân hàng và yêu cầu TLS/mTLS
Một công ty bảo hiểm ở Hà Nội tích hợp với một ngân hàng để thực hiện thu phí tự động qua API. Bản spec phiên bản đầu của BA chỉ ghi đúng một dòng: "Hệ thống gọi API ngân hàng qua HTTPS". Khi đến vòng đánh giá bảo mật của phía ngân hàng, họ trả về một loạt yêu cầu mà BA chưa lường: phải dùng TLS 1.2 trở lên, phải dùng mTLS (công ty bảo hiểm phải xin và cài chứng chỉ client do ngân hàng cấp), chứng chỉ có hạn 1 năm và phải có quy trình gia hạn, và IP gọi API phải nằm trong danh sách trắng (whitelist).
Vì spec ban đầu mơ hồ, dự án bị trễ 5 tuần để bổ sung hạ tầng chứng chỉ và làm lại tài liệu. Nếu BA hiểu rằng "in transit với đối tác tài chính" gần như luôn đòi hỏi mTLS, họ đã đưa các yêu cầu này vào ngay từ đầu và làm việc với kiến trúc sư về quy trình quản lý vòng đời chứng chỉ.
Bài học: Với dữ liệu in transit, đừng dừng ở "dùng HTTPS". Hãy ghi rõ phiên bản TLS tối thiểu, có cần mtTLS hay không, và đặc biệt là quy trình quản lý chứng chỉ — vì chứng chỉ hết hạn là nguyên nhân số một gây sập tích hợp trong thực tế.
Tình huống 3 — Bệnh viện và dữ liệu in use
Một hệ thống bệnh án điện tử cho chuỗi phòng khám tại Đông Nam Á lưu hồ sơ bệnh nhân với AES-256 at rest và TLS 1.3 in transit — nghe rất chuẩn. Nhưng đội phân tích dữ liệu nội bộ cần chạy thống kê trên dữ liệu bệnh nhân, nên họ tải toàn bộ dataset đã giải mã vào một máy chủ phân tích, để plaintext nằm trong RAM và cả trong các file tạm trên đĩa của máy đó. Một lỗ hổng phần mềm trên máy phân tích này đã để lộ memory, và dữ liệu nhạy cảm rò rỉ.
Đây chính là điểm mù in use: dữ liệu được bảo vệ rất tốt ở hai trạng thái kia, nhưng khi đem ra xử lý thì lại "cởi trần". Giải pháp đúng mà BA nên đề xuất: dùng data masking/anonymization cho môi trường phân tích (xóa tên, thay mã định danh bằng token), chỉ giải mã đúng những trường thực sự cần, và với dữ liệu cực nhạy cảm thì cân nhắc Confidential Computing (TEE) để việc tính toán diễn ra trong vùng nhớ cô lập.
Bài học: Một hệ thống "mã hóa đầy đủ" vẫn có thể rò rỉ ở trạng thái in use. BA cần đặc biệt soi vào các luồng analytics, báo cáo, môi trường test/staging — nơi dữ liệu thật hay bị sao chép và giải mã một cách vô tư.
Hướng dẫn từng bước
Khi viết spec liên quan đến mã hóa, hãy đi theo trình tự sau:
- Phân loại dữ liệu (data classification). Liệt kê các loại dữ liệu hệ thống xử lý và gắn nhãn mức nhạy cảm: Public, Internal, Confidential, Restricted. Số thẻ, CCCD, mật khẩu, dữ liệu y tế thuộc nhóm cao nhất. Đây là bước nền — không mã hóa tất cả mọi thứ, chỉ mã hóa cái cần.
- Lập ma trận ba trạng thái. Với mỗi loại dữ liệu nhạy cảm, điền vào bảng ba cột: At rest cần gì? In transit cần gì? In use cần gì? Ví dụ với số thẻ: at rest = column-level AES-256 + tokenization; in transit = TLS 1.2+; in use = chỉ gateway PCI giải mã, masking ở mọi nơi khác.
- Xác định cấp độ mã hóa at rest phù hợp. Hỏi: disk-level đủ chưa, hay cần TDE, hay cần column-level? Quy tắc: dữ liệu càng nhạy cảm, càng cần mã hóa ở cấp gần dữ liệu hơn (column-level).
- Đặt yêu cầu in transit rõ ràng. Ghi phiên bản TLS tối thiểu, có dùng mTLS không, chính sách chứng chỉ. Đừng quên cả lưu lượng nội bộ giữa các service, không chỉ lưu lượng ra Internet.
- Soi các điểm "in use". Truy luồng dữ liệu giải mã ở đâu: báo cáo, analytics, log, môi trường test. Yêu cầu masking/tokenization cho các luồng này.
- Viết yêu cầu quản lý khóa. Khóa lưu ở đâu (KMS/HSM), ai có quyền, chu kỳ xoay khóa, quy trình khi khóa bị lộ. Đây là phần BA hay quên nhất.
- Đối chiếu với quy định pháp lý. PCI-DSS cho thẻ, GDPR/Nghị định 13/2023 về bảo vệ dữ liệu cá nhân tại Việt Nam, ISO 27001. Mỗi quy định có yêu cầu mã hóa cụ thể.
Lỗi thường gặp & mẹo
- Nhầm "encryption" với "encoding" hay "hashing". Base64 là encoding, không bảo mật gì cả (ai cũng decode được). Hashing (SHA-256) là một chiều, dùng cho mật khẩu chứ không phải để giấu rồi lấy lại. Encryption mới là hai chiều có khóa. Đừng để dev nói "đã base64 rồi an toàn" qua mặt bạn.
- Mã hóa tất cả mọi thứ một cách máy móc. Mã hóa column-level mọi cột khiến không search/index được, hệ thống chậm và chi phí vận hành tăng. Hãy mã hóa có chọn lọc dựa trên phân loại dữ liệu.
- Quên dữ liệu in transit nội bộ. Nhiều người chỉ lo HTTPS ra Internet mà để traffic giữa các microservice trong cùng VPC chạy plaintext. Trong kiến trúc zero-trust hiện đại, traffic nội bộ cũng cần mã hóa.
- Bỏ quên backup và log. Database mã hóa nhưng file backup lại để trần, hoặc log ghi cả số thẻ ra file. Backup và log thường là điểm rò rỉ bị lãng quên — luôn đưa chúng vào spec.
- Hard-code khóa trong source code hoặc file config. Đây là lỗi kinh điển, khóa lọt lên Git là lộ vĩnh viễn. Yêu cầu dùng secrets manager/KMS.
- Mẹo về chứng chỉ: luôn yêu cầu cơ chế cảnh báo trước khi chứng chỉ TLS hết hạn. Sập hệ thống vì cert expired là sự cố production phổ biến và hoàn toàn tránh được.
Bài tập thực hành
Bối cảnh: Bạn là Technical BA cho một ứng dụng giao đồ ăn tại Việt Nam. Hệ thống xử lý các loại dữ liệu sau: thông tin tài khoản người dùng (tên, SĐT, email), địa chỉ giao hàng, thông tin thẻ tín dụng dùng thanh toán, và lịch sử đơn hàng. App giao tiếp với một payment gateway bên ngoài và một dịch vụ bản đồ.
Yêu cầu:
- Lập bảng phân loại dữ liệu cho 4 loại trên, gán mức nhạy cảm cho mỗi loại và giải thích ngắn.
- Với thông tin thẻ tín dụng và số điện thoại, lập ma trận ba trạng thái (at rest / in transit / in use), nêu cụ thể cơ chế bảo vệ bạn yêu cầu cho từng ô.
- Viết 3 yêu cầu phi chức năng (NFR) liên quan đến mã hóa cho hệ thống này, theo định dạng có thể kiểm thử được (ví dụ: "Toàn bộ giao tiếp với payment gateway phải dùng TLS 1.2 trở lên; kết nối dùng TLS dưới 1.2 phải bị từ chối").
- Chỉ ra một điểm "in use" tiềm ẩn rủi ro trong hệ thống này và đề xuất biện pháp giảm thiểu.
Tóm tắt
- Encryption biến plaintext thành ciphertext bằng khóa; độ an toàn nằm ở quản lý khóa, không phải giấu thuật toán.
- Dữ liệu luôn ở một trong ba trạng thái, mỗi trạng thái cần cơ chế riêng:
- Là Technical BA, công việc của bạn không phải mã hóa, mà là phân loại dữ liệu, lập ma trận ba trạng thái, đặt yêu cầu rõ ràng cho từng trạng thái, và không quên quản lý khóa.
- Tránh các bẫy kinh điển: nhầm encoding/hashing với encryption, mã hóa máy móc mọi thứ, quên traffic nội bộ, quên backup/log, hard-code khóa.
- Luôn đối chiếu với quy định pháp lý: PCI-DSS, Nghị định 13/2023, ISO 27001.