Quyền phải được kiểm tra ở phía server, tại tầng gần dữ liệu nhất, trên mọi endpoint — UI chỉ quyết định hiển thị.
Ẩn nút "Xoá" chỉ làm người dùng bình thường không thấy chức năng. Kẻ tấn công không dùng UI: họ mở DevTools, đọc bundle JS để biết endpoint tồn tại, rồi gọi thẳng DELETE /api/users/42 bằng curl. Mọi thứ chạy trên máy client — HTML ẩn, route bị disable, cờ isAdmin trong response — đều sửa được. Đây chính là lỗi Broken Function Level Authorization (API5): endpoint quản trị không được bảo vệ, chỉ "không được link tới".
Nguyên tắc cài đặt:
1. Mặc định từ chối. Middleware chặn tất cả, route nào công khai thì khai báo tường minh. Ngược lại (mặc định cho phép, nhớ chặn từng route) là kiểu thiết kế sớm muộn cũng sót.
2. Kiểm tra ở một chỗ, không rải rác. Đặt trong tầng service hoặc middleware chung, không copy điều kiện if (user.role === ...) vào từng controller — chỉ cần quên một chỗ là thủng.
3. Kiểm tra cả quyền chức năng lẫn quyền trên đối tượng. "Được xoá bài viết" khác "được xoá bài viết này". Xem thêm câu về IDOR/BOLA.
4. Danh tính lấy từ phiên/token đã verify, không bao giờ từ tham số client gửi lên (?userId=, header X-Role, trường role trong body).
5. Ghi log các lần từ chối để phát hiện dò quét.
UI vẫn nên ẩn thao tác không dùng được — đó là trải nghiệm, không phải kiểm soát truy cập.