Menu
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Đang tải...

Bài 31 — Authentication vs Authorization

Technical BA Masterclass Bài 31/60

Mở đầu — vì sao bài này quan trọng

Có một câu hỏi tôi rất hay hỏi các bạn BA trong buổi phỏng vấn: "Nếu một người dùng đăng nhập thành công vào hệ thống ngân hàng, nhưng lại xem được số dư của tài khoản người khác, thì đây là lỗi Authentication hay Authorization?" Bạn nào trả lời được rành mạch câu này gần như chắc chắn đã hiểu đúng bản chất bảo mật ở tầng nghiệp vụ. Đáng tiếc là phần lớn trả lời sai, hoặc lúng túng.

Trong tiếng Việt, cả hai từ này nhiều khi bị gọi chung là "phân quyền" hoặc "xác thực" lẫn lộn, dẫn đến viết requirement mơ hồ. Hậu quả không nhỏ: dev hiểu sai, tester bỏ sót case, và lỗ hổng bảo mật lọt ra production. Theo các báo cáo về lỗ hổng web (OWASP), "Broken Access Control" — tức lỗi liên quan trực tiếp đến Authorization — nhiều năm liền nằm ở vị trí số 1 trong Top 10 rủi ro phổ biến nhất. Tức là phần lớn sự cố bảo mật không phải vì hacker bẻ khóa mật khẩu siêu phàm, mà vì hệ thống cho phép người ta làm những việc lẽ ra họ không được phép.

Là Technical BA, bạn chính là người viết ra ranh giới "ai được làm gì". Nếu bạn không phân biệt rõ AuthN và AuthZ, spec của bạn sẽ tạo ra lỗ hổng. Bài này giúp bạn nắm chắc hai khái niệm, biết cách diễn đạt chúng trong tài liệu một cách rõ ràng để dev và tester không hiểu lầm.

Khái niệm cốt lõi

Authentication (AuthN) — "Bạn là ai?"

Authentication, viết tắt là AuthN, là quá trình xác minh danh tính của một chủ thể (người dùng, hệ thống, hoặc service). Câu hỏi cốt lõi của AuthN là: "Bạn có đúng là người bạn khai báo không?"

Khi bạn nhập email và mật khẩu để đăng nhập Gmail, hệ thống đang làm AuthN — kiểm tra xem bạn có thật sự là chủ tài khoản đó không. Khi bạn quẹt vân tay mở app MoMo, đó cũng là AuthN. Bản chất AuthN dựa trên việc bạn chứng minh một (hoặc nhiều) trong ba loại yếu tố sau:

  • Cái bạn biết (something you know): mật khẩu, mã PIN, câu hỏi bảo mật.
  • Cái bạn có (something you have): điện thoại nhận OTP, thẻ token vật lý, ứng dụng Authenticator.
  • Cái bạn là (something you are): vân tay, khuôn mặt, mống mắt — gọi chung là sinh trắc học (biometrics).
Khi hệ thống yêu cầu từ hai yếu tố trở lên, ta gọi đó là Multi-Factor Authentication (MFA) — xác thực đa yếu tố. Ví dụ kinh điển ở ngân hàng Việt Nam: nhập mật khẩu (cái bạn biết) rồi nhập tiếp mã OTP gửi về điện thoại hoặc Smart OTP (cái bạn có). Đây là yêu cầu bắt buộc theo quy định của Ngân hàng Nhà nước cho các giao dịch giá trị lớn.

Kết quả của AuthN thường là một session hoặc một token (ví dụ JWT) chứng minh rằng "người này đã được xác thực". Token đó sẽ được mang theo trong các request tiếp theo.

Các phương thức Authentication phổ biến

Là Technical BA, bạn cần biết tên gọi và đặc điểm của các cơ chế AuthN để viết spec đúng và trao đổi với architect:

  • Password-based: cổ điển nhất, người dùng nhập mật khẩu. Yêu cầu spec về độ phức tạp mật khẩu, hash lưu trữ (bcrypt, Argon2 — không bao giờ lưu plaintext), khóa tài khoản sau N lần sai.
  • OTP / MFA: gửi mã một lần qua SMS, email, hoặc app. Cần spec rõ thời gian sống của OTP (thường 60–300 giây), số lần nhập lại, kênh gửi.
  • Biometric: vân tay, FaceID — thường xử lý ở thiết bị, hệ thống chỉ nhận kết quả pass/fail.
  • SSO (Single Sign-On): đăng nhập một lần dùng cho nhiều ứng dụng, thường qua giao thức SAML hoặc OpenID Connect. Ví dụ: đăng nhập một lần vào hệ thống nội bộ công ty rồi vào được cả email, HR portal, ERP.
  • Social login: "Đăng nhập bằng Google/Facebook/Apple" — thực chất ủy thác việc xác thực cho bên thứ ba qua OpenID Connect.
  • Certificate / Mutual TLS: dùng giữa các hệ thống với nhau (server-to-server), xác thực bằng chứng chỉ số thay vì mật khẩu.
Lưu ý: cơ chế token và giao thức chi tiết như OAuth2, JWT đã được học sâu ở Bài 12. Ở bài này, ta tập trung vào sự phân biệt khái niệm AuthN và AuthZ chứ không đi lại vào chi tiết kỹ thuật token.

Authorization (AuthZ) — "Bạn được phép làm gì?"

Authorization, viết tắt là AuthZ, là quá trình quyết định một chủ thể đã được xác thực có quyền thực hiện một hành động cụ thể trên một tài nguyên cụ thể hay không. Câu hỏi cốt lõi là: "Bạn được phép làm gì với cái gì?"

Điểm mấu chốt: AuthZ luôn xảy ra sau AuthN. Bạn phải biết "ai" trước thì mới quyết định được "người đó được làm gì". Quay lại câu hỏi ở đầu bài: người dùng đăng nhập thành công (AuthN pass) nhưng xem được số dư tài khoản người khác — đây là lỗi Authorization, vì hệ thống không kiểm tra xem họ có quyền truy cập tài nguyên đó hay không.

Có vài mô hình AuthZ phổ biến mà BA cần biết:

  • RBAC (Role-Based Access Control) — phân quyền theo vai trò. Gán quyền cho từng vai trò (Admin, Manager, Staff), rồi gán vai trò cho người dùng. Phổ biến nhất, dễ quản lý. Ví dụ: vai trò "Kế toán" được duyệt chi dưới 50 triệu, "Trưởng phòng" được duyệt dưới 500 triệu.
  • ABAC (Attribute-Based Access Control) — phân quyền theo thuộc tính. Quyết định dựa trên thuộc tính của người dùng, tài nguyên và bối cảnh. Ví dụ: "nhân viên chi nhánh Hà Nội chỉ xem được hồ sơ khách hàng thuộc chi nhánh Hà Nội, trong giờ hành chính". Linh hoạt hơn nhưng phức tạp hơn.
  • ReBAC (Relationship-Based) — phân quyền theo quan hệ, kiểu Google Drive: "bạn xem được file này vì chủ file đã share cho bạn".
Một khái niệm quan trọng đi kèm AuthZ là nguyên tắc đặc quyền tối thiểu (Principle of Least Privilege): mỗi người chỉ nên có đúng quyền cần thiết để làm việc của mình, không hơn. BA cần thấm nguyên tắc này khi thiết kế ma trận phân quyền.

So sánh nhanh

Tiêu chíAuthentication (AuthN)Authorization (AuthZ)
Câu hỏiBạn là ai?Bạn được làm gì?
Xảy ra khi nàoTrướcSau AuthN
Kết quảToken/session xác nhận danh tínhCho phép/từ chối hành động
Lỗi tương ứngĐăng nhập sai, mạo danhTruy cập trái phép, leo thang đặc quyền
Mã HTTP điển hình401 Unauthorized403 Forbidden
Một mẹo nhỏ để nhớ mã lỗi HTTP (dù tên gọi gây nhầm): 401 Unauthorized thực ra nghĩa là "chưa xác thực" (lỗi AuthN), còn 403 Forbidden nghĩa là "đã xác thực nhưng không có quyền" (lỗi AuthZ).

Tình huống thực tế

Tình huống 1: Lỗ hổng IDOR ở ví điện tử

Một startup ví điện tử tại TP.HCM (gọi là PayViet cho dễ hình dung) ra mắt API xem lịch sử giao dịch: GET /api/v1/transactions?userId=10293. Hệ thống có AuthN rất tốt — bắt buộc OTP, MFA, mật khẩu mạnh. Người dùng phải đăng nhập mới gọi được API.

Vấn đề: backend chỉ kiểm tra "token có hợp lệ không" (AuthN), nhưng quên kiểm tra xem userId trong request có khớp với chủ token không (AuthZ). Một người dùng tò mò đổi userId=10293 thành userId=10294 và... xem được lịch sử giao dịch của người lạ. Đây là lỗ hổng kinh điển tên IDOR (Insecure Direct Object Reference) — một dạng Broken Access Control.

Khi điều tra, đội ngũ nhận ra spec ban đầu chỉ ghi: "API yêu cầu người dùng đã đăng nhập". Câu đó chỉ nói về AuthN. Không một dòng nào nói về AuthZ — rằng "người dùng chỉ được xem giao dịch của chính mình".

Bài học rút ra: AuthN pass không có nghĩa là an toàn. Là BA, khi viết spec cho mỗi endpoint, bạn phải tách bạch hai câu: (1) ai được gọi API này — AuthN; (2) họ được tác động lên dữ liệu của ai — AuthZ. Câu (2) bị bỏ sót là nguồn gốc của đa số sự cố rò rỉ dữ liệu.

Tình huống 2: Leo thang đặc quyền trong hệ thống nội bộ ngân hàng

Một ngân hàng thương mại cổ phần triển khai hệ thống phê duyệt khoản vay. Ma trận phân quyền theo RBAC: nhân viên tín dụng (Credit Officer) được tạo hồ sơ vay, trưởng phòng (Branch Manager) được duyệt hồ sơ.

Trong giai đoạn UAT, một tester phát hiện: màn hình của nhân viên tín dụng ẩn nút "Duyệt", nhưng nếu họ gọi thẳng API POST /loans/{id}/approve thì hệ thống vẫn cho duyệt. Lý do: việc phân quyền chỉ được làm ở giao diện (ẩn nút), còn backend không kiểm tra vai trò. Một nhân viên tín dụng về lý thuyết có thể tự tạo hồ sơ rồi tự duyệt khoản vay cho chính người thân — gọi là privilege escalation (leo thang đặc quyền), và phá vỡ nguyên tắc phân tách trách nhiệm (Segregation of Duties).

Bài học rút ra: Phân quyền phải được thực thi ở backend, không bao giờ chỉ dựa vào việc ẩn/hiện nút trên UI. Ẩn nút chỉ là trải nghiệm người dùng, không phải bảo mật. BA cần ghi rõ trong spec: "Endpoint approve phải kiểm tra người gọi có vai trò Branch Manager; nếu không, trả về 403." Và đặc biệt với nghiệp vụ tài chính, cần ghi rõ ràng buộc Segregation of Duties: người tạo không được là người duyệt.

Tình huống 3: SSO ở tập đoàn đa công ty

Một tập đoàn bán lẻ ở Đông Nam Á có 5 công ty con, dùng chung hệ thống SSO (đăng nhập một lần). Nhân viên đăng nhập một lần qua cổng trung tâm là vào được tất cả ứng dụng: ERP, CRM, hệ thống chấm công.

Ban đầu mọi người nghĩ "đã SSO rồi thì cứ vào được hết". Sai lầm. SSO chỉ giải quyết Authentication — xác nhận bạn là nhân viên hợp lệ của tập đoàn. Nhưng việc nhân viên công ty A có được xem dữ liệu lương của công ty B hay không lại là Authorization — và phải được xử lý riêng ở từng ứng dụng. Khi BA quên tách bạch điều này, nhân viên một công ty con suýt xem được dữ liệu nhạy cảm của công ty con khác chỉ vì "đã đăng nhập thành công".

Bài học rút ra: SSO làm AuthN dùng chung, nhưng AuthZ vẫn phải được quyết định cục bộ tại từng ứng dụng theo ngữ cảnh nghiệp vụ. Đăng nhập được vào hệ thống không đồng nghĩa với được phép truy cập mọi dữ liệu trong đó.

Hướng dẫn từng bước

Đây là quy trình tôi khuyên các bạn BA áp dụng khi đặc tả AuthN và AuthZ cho một tính năng:

Bước 1 — Liệt kê các actor (vai trò). Xác định ai sẽ dùng hệ thống: Khách hàng, Nhân viên giao dịch, Trưởng phòng, Admin, hệ thống bên thứ ba... Mỗi actor là một dòng trong ma trận phân quyền sau này.

Bước 2 — Đặc tả Authentication. Với mỗi actor, ghi rõ: phương thức đăng nhập (mật khẩu, MFA, SSO, API key?), yêu cầu độ mạnh mật khẩu, chính sách khóa tài khoản, thời gian sống của session/token. Trả lời câu hỏi "làm sao hệ thống biết đúng là người này?".

Bước 3 — Xây ma trận phân quyền (Authorization Matrix). Lập bảng: hàng là vai trò, cột là từng hành động/tài nguyên (Tạo đơn, Duyệt đơn, Xem báo cáo, Xóa user...). Đánh dấu được phép (✓) hay không. Đây là tài liệu cốt lõi của AuthZ.

Bước 4 — Bổ sung ràng buộc theo ngữ cảnh. Ngoài vai trò, có những ràng buộc theo thuộc tính/quan hệ: "chỉ xem dữ liệu chi nhánh mình", "chỉ sửa đơn do mình tạo", "chỉ truy cập trong giờ hành chính". Đây là phần ABAC, dễ bị bỏ sót nhất.

Bước 5 — Định nghĩa hành vi khi từ chối. Ghi rõ: khi chưa đăng nhập trả về 401, khi không đủ quyền trả về 403. Thông điệp lỗi hiển thị gì cho người dùng. Có ghi log audit không (rất quan trọng với nghiệp vụ tài chính).

Bước 6 — Yêu cầu thực thi ở backend. Ghi chú rõ ràng cho dev: mọi kiểm tra AuthZ phải thực hiện ở server, UI chỉ là lớp trải nghiệm. Đây là dòng spec cứu bạn khỏi lỗi như tình huống 2.

Lỗi thường gặp & mẹo

  • Nhầm lẫn AuthN và AuthZ trong câu chữ. Đừng viết chung chung "người dùng phải được phân quyền". Hãy tách: "phải đăng nhập" (AuthN) và "phải có quyền X trên tài nguyên Y" (AuthZ).
  • Chỉ đặc tả AuthN, quên AuthZ. Đây là lỗi phổ biến nhất và nguy hiểm nhất, dẫn thẳng tới IDOR như tình huống 1. Mỗi endpoint cần trả lời cả hai câu hỏi.
  • Phân quyền chỉ ở UI. Ẩn nút không phải bảo mật. Luôn yêu cầu kiểm tra ở backend.
  • Quên ràng buộc "dữ liệu của ai". Nhiều spec ghi "vai trò Staff được xem đơn hàng" nhưng quên ghi "chỉ đơn hàng của khách thuộc khu vực mình". Thiếu mệnh đề này là lỗ hổng.
  • Vai trò quá rộng (over-privileged). Đừng vì tiện mà cho mọi nhân viên vai trò gần giống Admin. Áp dụng nguyên tắc đặc quyền tối thiểu — cấp đúng cái cần, không hơn.
  • Mẹo dùng đúng mã HTTP. Nhớ 401 = chưa xác thực (AuthN), 403 = đã xác thực nhưng cấm (AuthZ). Việc dùng đúng giúp dev và tester hiểu ngay bản chất lỗi.
  • Mẹo "tách hai cột". Khi review spec một API bất kỳ, tự hỏi đúng hai câu: "Ai gọi được?" và "Họ tác động được lên dữ liệu của ai?". Trả lời đủ hai câu là bạn đã phủ cả AuthN lẫn AuthZ.

Bài tập thực hành

Bạn được giao đặc tả tính năng "Xem và tải bảng lương" cho một công ty với ba vai trò: Nhân viên, Trưởng phòng, Nhân sự (HR).

Yêu cầu nghiệp vụ: Nhân viên chỉ xem được bảng lương của chính mình. Trưởng phòng xem được bảng lương của nhân viên trong phòng mình (không xem được phòng khác). HR xem và tải được bảng lương của toàn công ty.

Hãy hoàn thành các phần sau:

  • Đặc tả Authentication: Phương thức đăng nhập nào phù hợp cho tính năng nhạy cảm về lương? Có nên yêu cầu MFA không? Tại sao?
  • Lập ma trận phân quyền: Vẽ bảng 3 vai trò × các hành động (Xem lương bản thân, Xem lương người trong phòng, Xem lương toàn công ty, Tải file). Đánh dấu được phép/không.
  • Ghi ràng buộc theo ngữ cảnh (ABAC): Viết chính xác mệnh đề giới hạn dữ liệu cho vai trò Trưởng phòng.
  • Hành vi từ chối: Khi một nhân viên cố gọi API xem lương người khác, hệ thống trả mã HTTP nào? Có ghi audit log không?
Gợi ý chấm: Một đáp án tốt phải tách bạch rõ AuthN ở mục 1 và AuthZ ở mục 2–3, đồng thời mục 3 phải có mệnh đề "chỉ phòng mình" — nếu thiếu, đó chính là lỗ hổng Broken Access Control.

Tóm tắt

  • Authentication (AuthN) trả lời "bạn là ai" — xác minh danh tính qua mật khẩu, OTP, MFA, SSO, sinh trắc học. Authorization (AuthZ) trả lời "bạn được làm gì" — quyết định quyền truy cập tài nguyên, theo mô hình RBAC, ABAC, ReBAC.
  • AuthZ luôn xảy ra sau AuthN. Đăng nhập thành công không đồng nghĩa với được phép làm mọi thứ.
  • Lỗi AuthZ (Broken Access Control) là rủi ro bảo mật phổ biến nhất. Nguyên nhân thường gặp: spec chỉ ghi AuthN mà quên AuthZ, hoặc phân quyền chỉ làm ở UI.
  • Là BA, công cụ cốt lõi của bạn là ma trận phân quyền kèm các ràng buộc theo ngữ cảnh ("dữ liệu của ai", "trong điều kiện nào"), và yêu cầu thực thi ở backend.
  • Hai câu hỏi vàng cho mỗi tính năng: "Ai gọi được?" (AuthN) và "Họ tác động được lên dữ liệu của ai?" (AuthZ). Trả lời đủ cả hai, spec của bạn sẽ kín kẽ.