Menu
ESC

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

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

Đang tải...

Bài 41 — Authentication vs Authorization

Technical Product Manager Bài 41/60

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

Có một cuộc đối thoại mà gần như mọi Technical PM đều từng chứng kiến trong phòng họp. Đội kỹ thuật báo cáo: "Chúng ta vừa bị một sự cố. Một người dùng đã xem được hoá đơn của người dùng khác." Người quản lý hỏi: "Hệ thống đăng nhập của mình bị hack à?" Và kỹ sư trả lời: "Không, đăng nhập vẫn ổn. Người đó đăng nhập đúng là chính họ. Vấn đề là họ truy cập được dữ liệu không thuộc về họ."

Đó chính là khoảnh khắc mà sự khác biệt giữa Authentication (xác thực)Authorization (phân quyền) trở nên cực kỳ quan trọng. Hai khái niệm này nghe na ná nhau, đều viết tắt bắt đầu bằng "Auth", và bị rất nhiều người — kể cả PM lẫn kỹ sư — dùng lẫn lộn. Nhưng chúng giải quyết hai câu hỏi hoàn toàn khác nhau, và việc nhầm lẫn chúng là nguồn gốc của một tỷ lệ rất lớn các lỗ hổng bảo mật nghiêm trọng.

Là một Technical PM, bạn không cần tự tay viết code xác thực. Nhưng bạn phải hiểu đủ sâu để: viết acceptance criteria chính xác cho tính năng có liên quan đến quyền truy cập, đặt câu hỏi đúng khi review một thiết kế, và nhận ra khi nào một yêu cầu sản phẩm tưởng vô hại lại đang mở ra một lỗ hổng phân quyền. Bài này sẽ giúp bạn tách bạch rõ ràng hai khái niệm, và quan trọng hơn, biết cách áp dụng chúng vào công việc hàng ngày.

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

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

Authentication trả lời câu hỏi: người (hoặc hệ thống) đang yêu cầu truy cập thực sự là ai? Nó là quá trình xác minh danh tính. Khi bạn nhập email và mật khẩu vào Shopee rồi đăng nhập thành công, hệ thống đã xác thực rằng bạn đúng là chủ tài khoản đó.

Có nhiều "bằng chứng" (factor) mà hệ thống dùng để xác thực danh tính, thường chia thành ba nhóm:

  • Thứ bạn biết (something you know): mật khẩu, mã PIN, câu hỏi bảo mật.
  • Thứ bạn có (something you have): điện thoại nhận OTP qua SMS, ứng dụng Google Authenticator sinh mã, hardware key như YubiKey.
  • Thứ bạn là (something you are): vân tay, khuôn mặt (Face ID), giọng nói — gọi chung là sinh trắc học (biometric).
Khi một hệ thống yêu cầu từ hai nhóm trở lên, ta gọi đó là Multi-Factor Authentication (MFA) hoặc hai lớp (2FA). Ví dụ: nhập mật khẩu (thứ bạn biết) rồi nhập thêm mã OTP gửi về điện thoại (thứ bạn có). MFA mạnh hơn nhiều vì kẻ tấn công phải đánh cắp được cả hai yếu tố cùng lúc — biết mật khẩu thôi chưa đủ.

Một điểm quan trọng cho PM: không phải mọi yếu tố đều an toàn như nhau. OTP qua SMS tiện lợi và phổ biến ở Việt Nam, nhưng dễ bị tấn công SIM-swap (kẻ gian chiếm quyền số điện thoại của bạn tại nhà mạng) hoặc bị chặn tin nhắn. Ứng dụng authenticator hay hardware key an toàn hơn nhiều. Đây là loại trade-off mà PM cần cân nhắc giữa trải nghiệm và bảo mật.

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

Authorization trả lời câu hỏi khác hẳn: một khi đã biết bạn là ai, bạn được phép truy cập tài nguyên nào và thực hiện hành động gì? Nó là quá trình kiểm tra quyền hạn.

Hãy hình dung một toà nhà văn phòng. Authentication là lúc bảo vệ kiểm tra thẻ nhân viên ở sảnh — xác nhận bạn đúng là nhân viên công ty. Authorization là chuyện cái thẻ đó có quẹt mở được cửa phòng server hay không. Bạn vào được toà nhà (đã xác thực), nhưng không có nghĩa bạn vào được mọi phòng (chưa được phân quyền cho phòng server).

Authorization luôn diễn ra sau authentication. Bạn phải biết "ai" trước khi quyết định "được làm gì". Một số mô hình phân quyền phổ biến mà PM sẽ gặp:

  • RBAC (Role-Based Access Control) — phân quyền theo vai trò. Người dùng được gán vai trò (admin, biên tập viên, khách), mỗi vai trò có một bộ quyền cố định. Đây là mô hình phổ biến nhất và dễ giải thích nhất cho stakeholder.
  • ABAC (Attribute-Based Access Control) — phân quyền theo thuộc tính. Quyền được tính dựa trên thuộc tính của người dùng, tài nguyên và ngữ cảnh (ví dụ: "nhân viên thuộc phòng kế toán, chi nhánh Hà Nội, trong giờ làm việc mới được xem báo cáo này"). Linh hoạt hơn nhưng phức tạp hơn.
  • Ownership-based — phân quyền theo quyền sở hữu. Người dùng chỉ thao tác được trên tài nguyên thuộc về chính họ (đơn hàng của tôi, bài đăng của tôi).

Một bảng so sánh để khắc cốt ghi tâm

Authentication (AuthN)Authorization (AuthZ)
Câu hỏiBạn là ai?Bạn được làm gì?
Diễn ra khi nàoTrướcSau
Ví dụĐăng nhập, OTP, Face IDKiểm tra vai trò, quyền sở hữu
Lỗi điển hìnhĐăng nhập sai bị từ chối (401)Truy cập tài nguyên cấm (403)
Ghi nhớ nhanh: mã lỗi HTTP 401 Unauthorized thực ra nói về authentication thất bại (chưa chứng minh được bạn là ai — dù tên gọi gây hiểu nhầm), còn 403 Forbidden nói về authorization thất bại (biết bạn là ai rồi nhưng bạn không có quyền).

Tình huống thực tế

Tình huống 1 — Sàn TMĐT và lỗ hổng xem đơn hàng người khác

Một sàn thương mại điện tử giả định tên TikiGo có API lấy chi tiết đơn hàng: GET /api/orders/10293. Người dùng đăng nhập xong, mở đơn hàng của mình, mọi thứ hoạt động trơn tru. Đội kỹ thuật đã làm authentication rất tốt: phải có token đăng nhập hợp lệ mới gọi được API.

Vấn đề nằm ở chỗ một khách hàng tò mò đổi số trên thanh địa chỉ từ 10293 thành 10294, và... thấy được đơn hàng của một người hoàn toàn xa lạ, kèm tên, số điện thoại, địa chỉ giao hàng. Hệ thống đã xác thực đúng người dùng, nhưng quên kiểm tra quyền sở hữu: nó không hỏi "đơn hàng 10294 có thuộc về người đang đăng nhập không?".

Đây là lỗ hổng kinh điển tên là IDOR (Insecure Direct Object Reference) — một dạng lỗi authorization. Authentication hoàn hảo không cứu được bạn, vì người tấn công ở đây là một người dùng đã đăng nhập hợp lệ.

Bài học rút ra: Là PM, khi viết user story dạng "người dùng xem được đơn hàng của mình", từ "của mình" chính là một yêu cầu authorization phải được ghi rõ trong acceptance criteria. Đừng giả định kỹ sư sẽ tự nhớ. Hãy viết: "Hệ thống PHẢI từ chối (403) nếu đơn hàng không thuộc về người dùng đang đăng nhập."

Tình huống 2 — Ngân hàng số và sự cố quyền của nhân viên hỗ trợ

Một ngân hàng số tại Đông Nam Á (gọi là VBank) có đội chăm sóc khách hàng dùng công cụ nội bộ để tra cứu giao dịch khi khách gọi than phiền. Ban đầu, để tiện, đội kỹ thuật cấp cho mọi nhân viên hỗ trợ quyền xem toàn bộ lịch sử giao dịch của mọi tài khoản. Authentication rất chặt — nhân viên phải dùng MFA với hardware key mới đăng nhập được công cụ nội bộ.

Sáu tháng sau, một nhân viên bị phát hiện đã tra cứu sao kê của một người nổi tiếng vì tò mò cá nhân, rồi rò rỉ ra ngoài. Đây không phải lỗi authentication — nhân viên đó đăng nhập hoàn toàn hợp lệ. Đây là lỗi authorization: hệ thống cấp quyền quá rộng (over-privileged), vi phạm nguyên tắc least privilege (đặc quyền tối thiểu — chỉ cấp đúng quyền cần cho công việc).

VBank sau đó tái thiết kế theo RBAC kết hợp ABAC: nhân viên hỗ trợ chỉ xem được giao dịch của khách hàng đang có ticket hỗ trợ mở trong vòng 24 giờ, và mọi lượt truy cập đều ghi log (audit trail). Số lượt truy cập "bất thường" giảm 90% chỉ trong tháng đầu.

Bài học rút ra: Authorization không chỉ là chặn người ngoài, mà còn là kiểm soát người trong. PM cần hỏi: "Người dùng nội bộ này thực sự cần quyền gì để làm việc?" thay vì cấp rộng cho tiện. Và đừng quên audit log — nó vừa răn đe vừa giúp điều tra khi có sự cố.

Tình huống 3 — Ứng dụng SaaS và sự nhầm lẫn 401 với 403

Một startup SaaS quản lý nhân sự tại TP.HCM ra mắt tính năng phân quyền: gói Basic không được dùng báo cáo nâng cao, chỉ gói Pro mới được. Khi người dùng gói Basic bấm vào báo cáo nâng cao, hệ thống trả về lỗi 401 và... tự động đăng xuất họ ra ngoài, bắt đăng nhập lại. Người dùng hoảng loạn, gửi hàng loạt ticket nghĩ rằng tài khoản bị lỗi.

Nguyên nhân: kỹ sư dùng nhầm mã lỗi. Người dùng đã xác thực hoàn toàn đúng (họ là họ), chỉ là không được phân quyền dùng tính năng đó. Đúng ra phải trả 403 Forbidden kèm thông báo "Tính năng này thuộc gói Pro — nâng cấp ngay". Việc trả 401 khiến frontend hiểu nhầm là phiên đăng nhập hết hạn nên đá người dùng ra.

Bài học rút ra: Sự nhầm lẫn AuthN/AuthZ không chỉ gây lỗ hổng bảo mật mà còn phá hỏng trải nghiệm. Với một PM, đây thậm chí là cơ hội: một lỗi 403 đúng chỗ có thể trở thành điểm chạm bán hàng (upsell). Phân biệt rõ hai loại lỗi giúp bạn thiết kế đúng cả về kỹ thuật lẫn sản phẩm.

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

Khi bạn — với tư cách PM — làm việc trên bất kỳ tính năng nào động đến quyền truy cập, hãy đi theo quy trình sau:

  • Tách câu hỏi thành hai vế. Với mỗi hành động trong tính năng, tự hỏi tách bạch: "Hệ thống cần xác minh ai đang làm việc này (AuthN)?" và "Người đó được phép làm việc này không (AuthZ)?" Viết riêng hai dòng.
  • Lập danh sách vai trò và quyền. Vẽ một bảng ma trận: hàng là vai trò (khách, người dùng thường, admin, nhân viên hỗ trợ...), cột là hành động (xem, tạo, sửa, xoá). Đánh dấu ô nào được phép. Bảng này là tài liệu sống mà cả kỹ sư lẫn QA đều dùng được.
  • Áp dụng least privilege. Với mỗi vai trò, mặc định cấp ít quyền nhất, chỉ mở thêm khi có lý do nghiệp vụ rõ ràng. Đừng bắt đầu bằng "cấp hết cho tiện rồi siết sau" — bạn sẽ không bao giờ siết kịp.
  • Viết acceptance criteria cho cả mặt tiêu cực. Đừng chỉ viết "người dùng xem được đơn hàng của mình". Hãy thêm: "Người dùng KHÔNG xem được đơn hàng của người khác, hệ thống trả 403." Mặt tiêu cực (negative test) chính là nơi lỗ hổng ẩn nấp.
  • Yêu cầu audit log cho hành động nhạy cảm. Mọi truy cập vào dữ liệu nhạy cảm (tài chính, thông tin cá nhân) nên được ghi lại: ai, lúc nào, truy cập gì. Đây vừa là yêu cầu tuân thủ (như Nghị định 13 ở Việt Nam) vừa là công cụ điều tra.
  • Rà soát điểm chuyển giao quyền. Chú ý các luồng dễ sót: chia sẻ link công khai, mời thành viên vào nhóm, đổi vai trò người dùng, gọi API trực tiếp không qua giao diện. Đây là nơi authorization hay bị "quên".

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

  • Nhầm "đã đăng nhập" là "được phép". Sai lầm phổ biến nhất. Đăng nhập hợp lệ chỉ chứng minh danh tính, không tự động cho quyền. Luôn kiểm tra quyền ở tầng máy chủ cho mỗi yêu cầu.
  • Chỉ ẩn nút trên giao diện rồi tưởng đã an toàn. Ẩn nút "Xoá" với người dùng thường là tốt cho UX, nhưng kẻ tấn công có thể gọi thẳng API bỏ qua giao diện. Authorization PHẢI được kiểm tra ở backend, không bao giờ chỉ ở frontend. Đây là điều PM nên hỏi mỗi khi review: "Quyền này kiểm tra ở server hay chỉ ẩn trên UI?"
  • Quên kiểm tra quyền sở hữu (IDOR). Như tình huống TikiGo. Mẹo: mỗi khi API có một định danh tài nguyên (/orders/{id}, /files/{id}), hãy hỏi "có đoạn nào kiểm tra tài nguyên này thuộc về người gọi không?".
  • Dùng nhầm 401 và 403. 401 = chưa xác thực / xác thực hỏng. 403 = đã xác thực nhưng không có quyền. Dùng đúng giúp frontend xử lý đúng và trải nghiệm rõ ràng.
  • Cấp quyền quá rộng vì ngại làm phức tạp. Nhớ nguyên tắc least privilege. "Cấp ít, mở dần" luôn an toàn hơn "cấp nhiều, siết sau".
  • Mẹo cho PM: Trong mọi buổi review thiết kế kỹ thuật có dính tới dữ liệu người dùng, hãy biến hai câu hỏi này thành thói quen — "Phần này xác thực thế nào?" và "Phần này phân quyền thế nào?". Tách bạch hai câu hỏi đã giúp bạn vượt qua phần lớn kỹ sư lười.

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

  • Phân loại nhanh. Với mỗi tình huống sau, xác định đó là vấn đề AuthN hay AuthZ: (a) Người dùng nhập sai mật khẩu ba lần và bị khoá. (b) Một biên tập viên cố xoá bài của tổng biên tập nhưng bị từ chối. (c) Hệ thống yêu cầu nhập OTP sau khi nhập mật khẩu. (d) Người dùng gói miễn phí không tải được file dung lượng lớn.
  • Viết acceptance criteria. Cho tính năng "Quản lý nhóm trong ứng dụng chat": trưởng nhóm có thể xoá thành viên, thành viên thường thì không. Hãy viết ít nhất 3 acceptance criteria bao gồm cả mặt tiêu cực (ai KHÔNG được làm gì) và mã lỗi tương ứng.
  • Lập ma trận quyền. Cho một ứng dụng blog có ba vai trò (Khách, Tác giả, Quản trị) và bốn hành động (Đọc bài, Viết bài, Sửa bài bất kỳ, Xoá bài bất kỳ). Vẽ bảng ma trận đánh dấu ai được làm gì, áp dụng nguyên tắc least privilege.
  • Soi lỗ hổng. API GET /api/users/{id}/payslip (xem phiếu lương) hiện chỉ kiểm tra người gọi đã đăng nhập. Hãy chỉ ra lỗ hổng và đề xuất một dòng yêu cầu authorization để vá nó.

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, sinh trắc học, hardware key. Nhiều yếu tố kết hợp lại thành MFA, an toàn hơn một yếu tố đơn lẻ.
  • Authorization (AuthZ) trả lời "Bạn được làm gì?" — kiểm tra quyền hạn dựa trên vai trò (RBAC), thuộc tính (ABAC) hoặc quyền sở hữu. Luôn diễn ra sau authentication.
  • Đăng nhập hợp lệ KHÔNG đồng nghĩa được phép. Phần lớn lỗ hổng nghiêm trọng (như IDOR) là lỗi authorization xảy ra với người dùng đã xác thực.
  • Authorization phải kiểm tra ở backend, không bao giờ chỉ ẩn nút trên giao diện. Áp dụng least privilege và ghi audit log cho hành động nhạy cảm.
  • 401 = xác thực hỏng; 403 = không có quyền. Dùng đúng giúp cả bảo mật lẫn trải nghiệm.
  • Với PM: tách mọi tính năng động đến quyền truy cập thành hai câu hỏi AuthN/AuthZ, viết acceptance criteria cho cả mặt tiêu cực, và biến chúng thành câu hỏi thường trực trong mỗi buổi review thiết kế.