📋 What Is This Control?
Implement Access Control is the proactive practice of deciding, for every attempted operation, whether the authenticated subject is permitted to perform that action on that specific resource. Authentication answers "who are you?"; access control answers "are you allowed to do this?" - and it must run server-side, on every request, against the specific record. It operationalizes least privilege and deny-by-default, and it is the primary defense against the Broken Access Control risk (A01).
🎯 What It Prevents
- IDOR / BOLA: Reading another user's record by swapping an identifier
- Function-Level Escalation: A standard user calling an admin endpoint directly
- Horizontal Escalation: Cross-tenant access via a supplied account_id
- Parameter / Metadata Tampering: Trusting a client-sent
role=admin - Forced Browsing: Reaching unlinked, staging, or legacy endpoints
- Direct File Access: Guessing a predictable path to a stored file
- Unchecked Write Verbs: DELETE/PUT on a non-owned resource
- Undetected Enumeration: Probing IDs at scale with no alerting
🧭 How It Works
↓
2. Load the specific target resource
↓
3. Ask the central policy: may THIS subject do THIS action on THIS resource?
↓
4. Default answer is DENY - allow only on explicit grant
↓
5. Log the decision; the ownership check stops IDOR & escalation
❌ Without This Control
✅ Applying the Control
✓ Implementation Checklist
- Default decision is deny; access requires an explicit grant
- Every decision is made server-side; no authority from client input
- Authorization is centralized in one reviewable component
- Every object reference has a record-level ownership/tenant check
- The ownership check covers every verb (read, create, update, delete)
- Least privilege: new subjects default low; elevation is scoped and revocable
- Sensitive functions gated by a server-side check, not the UI
- Protected files served through an authorizing handler
- Token claims verified; permissions re-checked against server state
- Access-control failures are logged and alerted on
- Policy is auditable and covered by negative tests
🔍 Tools & Techniques
Authorization Models & Engines:
Testing & Review:
How to Verify:
- Test that a non-owner is denied on every protected resource (403/404)
- Test that a lower-privilege user cannot call admin endpoints
- Confirm a client-supplied role in the body is ignored
- Probe for IDOR by incrementing/swapping identifiers
- Forced-browse unlinked and staging endpoints
- Verify DELETE/PUT are authorized, not just GET
🌍 Why It Matters
- Broken Object-Level Authorization (IDOR/BOLA): Serving a record by id with no owner check recurs across banking, healthcare, e-commerce, and social platforms; a record-level ownership check stops it.
- Privilege escalation via unprotected function: An admin action reachable because the UI hid the link - closed by a deny-by-default server-side gate.
- Forced browsing to unlinked resources: When obscurity is the only barrier, discovery equals access; enforced authorization on the resource itself is the fix.
- Metadata / parameter tampering: A request carrying its own authority (
role=admin) is defeated by deriving authority solely from server-side state.
These are documented vulnerability classes; OWASP ranks Broken Access Control the #1 web application risk. Implementing C1 well drives that risk toward zero.
📌 Quick Tips
- DO NOT read role/account_id from client input for a decision
- DO NOT rely on hidden UI as a control
- DO NOT treat an unguessable ID as access control
- DO check record-level ownership on every reference
- DO centralize the authorization decision
- DO apply the check to every verb
- DO log denials and test the negative cases