Blog về kiểm thử ·

Authentication và authorization: QA nên kiểm quyền truy cập thế nào

Nhiều lỗi bảo mật nghiêm trọng bắt đầu từ nhầm lẫn đơn giản: hệ thống biết bạn là ai, nhưng quên kiểm object có thuộc về bạn không.

Mô hình kiểm quyền
  1. Không token: 401
  2. Token sai: 401
  3. Đúng user, sai role: 403 hoặc không có action
  4. Đúng role, sai object: 403 hoặc 404

Authentication trả lời “bạn là ai?”

Authentication là login, password, token, session và expiry. Nó chứng minh danh tính nhưng không quyết định bạn được xem gì.

Hãy kiểm thông tin đúng, password sai, email viết hoa, thiếu token, token hết hạn và logout.

Authorization trả lời “bạn được làm gì?”

Authorization kiểm role và quyền sở hữu object. User đã login vẫn không được mở đơn hàng hay tài khoản của người khác.

API hay lỗi ở đây vì id dễ đoán, còn nút ẩn trên frontend không bảo vệ backend.

Kiểm quyền sở hữu object

Dùng hai user. Mở object bằng owner, ghi id, rồi gọi id đó bằng token user thứ hai. Thường expected là 403 hoặc 404.

Vì sao đôi khi 404 tốt hơn

Với object riêng tư, 404 che luôn việc object có tồn tại hay không. 403 cho biết nó tồn tại nhưng bạn không được xem.

Kiểm role

Role phải kiểm cả UI lẫn API. Nếu nút admin bị ẩn, vẫn gửi request bằng token user thường.

Nút ẩn là tiện ích. Request bị từ chối mới là bảo mật.

Access bug thường gặp

Thiếu filter owner, chỉ kiểm role ở frontend, token vẫn dùng được sau logout, endpoint lộ khác biệt giữa object riêng tư tồn tại và không tồn tại.

Bug report về access cần hai account, ngữ cảnh token và object id.

Matrix actor × action × object

Danh sách role là chưa đủ. Tạo row như manager A đọc client A, manager A sửa client B, user thường gọi admin endpoint, nhân viên cũ dùng token cũ. Mỗi row cần expected allow, deny hoặc hide.

Đừng chỉ test GET. BOLA có thể đã chặn read nhưng còn trong PATCH, DELETE, bulk endpoint, export hoặc id lồng trong body. UUID khó đoán hơn nhưng không thay permission check phía server.

Access matrix tối thiểu
Actor       Action  Object        Expected\nmanager A   GET     client A      200\nmanager A   GET     client B      403/404 theo contract\nmanager A   PATCH   client B      403/404, data không đổi\nviewer      DELETE  client A      403\nno token    GET     client A      401 + WWW-Authenticate

Vòng đời session và token

Kiểm issue, rotation sau login hoặc đổi quyền, expiry, refresh, logout, revoke, đổi password và nhiều thiết bị. Một số architecture cho access token cũ sống tới expiry ngắn; khi đó logout phải revoke refresh và UI không được hứa hơn server.

  • Session id đổi sau login để ngăn session fixation.
  • Cookie có Secure, HttpOnly, SameSite phù hợp; token không lộ trong URL hoặc log.
  • Token hết hạn, hỏng hoặc ký sai key bị từ chối.
  • Thay đổi role đến permission check trong thời gian đã thống nhất dù có cache.
  • Refresh reuse, logout và đổi password theo policy đã document.

BOLA, BFLA và quyền trên field

BOLA là user được gọi function nhưng backend không kiểm object id cụ thể. BFLA là role không được gọi function, ví dụ manager gọi admin export. Lỗi property-level làm lộ hoặc nhận field mà role không được dùng.

Trong CRM, hãy test client id của người khác, admin-only bulk export và PATCH có owner_id hoặc is_vip mà form không hiển thị. Ẩn button không xử lý các risk phía server này.

Ví dụ thực tế: ba lỗi phân quyền khác nhau trong CRM

Một lần kiểm client của người khác chưa chứng minh hệ thống an toàn. Dùng hai manager cùng tenant, một admin và một viewer chỉ đọc. Tạo client giả có owner rõ ràng. Sau đó kiểm ba ranh giới độc lập: object, function và field.

Actor × action × object
  1. Xác định role và owner của object.
  2. Gọi id object của người khác.
  3. Gọi thẳng function chỉ dành cho admin.
  4. Thử ghi một property bị cấm.

BOLA: function được dùng, object của người khác

Manager B được gọi GET /clients/{id} với client của mình. Dùng token B gửi id client A và mong đợi 403 hoặc 404 theo contract, không lộ dữ liệu A. Lặp lại với PATCH và DELETE trong môi trường test, cả id nằm trong body. UUID khó đoán không phải kiểm quyền: id có thể lọt qua export hoặc link.

BFLA: cả function bị cấm

Export hàng loạt hoặc đổi owner có thể chỉ dành cho admin. Ẩn button không chứng minh gì; gọi trực tiếp admin endpoint với token B. Kiểm request bị từ chối và không có tác dụng phụ: không tạo file export, không đổi owner hay đẩy event vào queue. So với lời gọi thành công của admin để tránh nhầm endpoint hỏng với authorization đúng.

Property-level: function hợp lệ, field bị cấm

Manager có thể sửa số điện thoại client của mình nhưng không được sửa `owner_id` hay `is_vip`. Thêm các field này vào PATCH bằng Postman dù UI không hiển thị. Đọc lại object với quyền admin để chắc field bị cấm không đổi. Response 200 âm thầm bỏ qua chỉ đúng nếu contract quy định. Kiểm cả việc viewer có đọc được field nhạy cảm không.

Thêm tenant và vòng đời quyền

Trong CRM nhiều tenant, hai user cùng role ở hai tổ chức khác nhau cần case cross-tenant riêng. Sau khi thu hồi role hay chuyển owner, thử lại token cũ và đo độ trễ cache theo tài liệu. Logout, 401 so với 403 và cách che object bằng 404 phải theo chính sách sản phẩm, không theo sở thích tester.

Ma trận từ chối tối thiểu
Actor       Request                         Expected\nmanager B   GET /clients/A                  deny; no A data\nmanager B   PATCH /clients/A                deny; no write\nmanager B   POST /admin/clients/export       deny; no file\nmanager A   PATCH /clients/A {is_vip:true}  deny/ignore per contract\nviewer      GET /clients/A                  only safe fields\nno token    GET /clients/A                  401
Bằng chứng cần có gì?

Với mỗi request bị chặn, lưu role, id, method, status, response đã che PII và bằng chứng không có tác dụng phụ. Report riêng ba loại lỗi vì nguyên nhân và cách sửa khác nhau. Nếu truy cập được dữ liệu thật của người khác, escalate qua kênh bảo mật riêng.

Tình huống thứ hai: quyền sau khi đổi manager phụ trách

CRM chuyển client từ manager A sang B. Cả hai đã đăng nhập và permission được cache. B phải có quyền trong khoảng thời gian đã thống nhất, còn A phải mất quyền. Đăng nhập lại không đủ để kiểm: token và link cũ của A có thể vẫn dùng được.

Định nghĩa chính sách thời gian

Hỏi thu hồi quyền tức thì hay cho phép độ trễ cache ngắn. “Đến lần đăng nhập sau” có thể không phù hợp với dữ liệu nhạy cảm, nhưng QA không tự bịa TTL. Ghi thời gian tối đa và nguồn sự thật: owner_id, permission service hay claim trong token. Chuẩn bị hai session đang hoạt động và đồng hồ có thể kiểm soát.

Kiểm quyền trước và sau

Trước khi chuyển: A đọc/sửa, B bị từ chối; sau thời hạn: ngược lại. Kiểm GET, PATCH, danh sách client, export và task liên kết vì endpoint có thể filter khác nhau. Gọi API trực tiếp với token cũ của A quan trọng hơn việc card biến mất khỏi UI. Request bị từ chối không được ghi dữ liệu một phần.

Thử race khi chuyển quyền

PATCH của A chạy đồng thời với reassignment cần quy tắc thứ tự: nó có thể bắt đầu trước khi owner_id đổi nhưng commit sau. Nếu contract chưa xác định điểm quyết định, hãy nêu câu hỏi. Lưu timestamp, phiên bản object và correlation id của hai request. Kết quả thứ tự khác nhau trong một lần chạy chưa chắc là defect.

Kiểm field và lịch sử

A có thể mất quyền trên card hiện tại nhưng vẫn tìm thấy dữ liệu trong activity, search hoặc export. B thấy card nhưng không thấy deal hay task vì owner_id trên object liên kết vẫn cũ. Liệt kê resource và expected access; đôi khi manager cũ hợp lệ giữ quyền xem audit, đôi khi không. Làm rõ rule thay vì đoán.

Đo mà không làm lộ dữ liệu

Dùng account và client giả. Ghi role, tuổi token, thời điểm chuyển quyền, response và việc không có write sau mỗi bước. Không đính kèm card khách hàng thật vào issue công khai. Nếu quyền cũ còn hiệu lực, báo chính xác thời gian, method và object thay vì “cache đôi khi bị cũ”.

Ma trận chuyển owner
Time                  A GET/PATCH   B GET/PATCH\nbefore reassignment   allow         deny\nafter agreed TTL      deny          allow\nold token A           deny          —\nsearch/export A       no client A   —\nlinked tasks          per ownership policy
Bằng chứng đủ là gì?

Không chỉ owner_id đổi trong storage, mà hành vi nhất quán trên đường đọc và ghi sau mốc thời gian đã thống nhất. Token cũ còn dùng quá lâu là phát hiện bảo mật riêng, kèm thời lượng đo được trên dữ liệu test.

Câu hỏi thường gặp về access

Object riêng tư của user khác nên trả 403 hay 404?

Cả hai có thể đúng theo contract. 404 giấu việc object tồn tại, 403 nói rõ bị từ chối. Điều bắt buộc là nhất quán, không lộ data và không thực hiện action.

UUID có ngăn BOLA không?

Không. UUID giảm khả năng đoán nhưng id có thể lộ qua link, log, export hoặc response. Server vẫn phải kiểm authorization cho từng object.

Kiểm role qua UI đã đủ chưa?

Chưa. Control bị ẩn chỉ cải thiện UX; request vẫn gửi trực tiếp được. Server phải authorize mọi method và object.

Kiểm access ít bước nhưng tác động lớn: đôi khi chỉ đổi một id là thấy backend có bảo vệ dữ liệu thật hay không.

Luyện trên dịch vụ đang chạy Bài tiếp theo

← Tất cả bài viết