Authorisation and Access Control in Application Design
Authorisation determines what an authenticated user is allowed to do. Broken access control is the OWASP Top 10 number one vulnerability — more common and impactful than almost any other category. Getting it right requires careful design, not just implementation.
Common Access Control Failures
- Insecure direct object references (IDOR): Accessing a resource by incrementing an ID in the URL — e.g. changing /invoice/1234 to /invoice/1235 and accessing another user's invoice
- Missing function-level access control: API endpoints that check authentication but not authorisation — any authenticated user can call administrative functions
- Privilege escalation: Users modifying their own role or permissions through unprotected parameters
- Path traversal: Using relative paths (../../) to access files outside intended directories
Access Control Design Principles
- Default deny: Access should be denied by default and explicitly granted — not the reverse
- Enforce on the server: All authorisation checks must happen server-side — client-side UI hiding is not an access control
- Check at every request: Authorisation must be re-verified on every request — not just at login
- Use indirect references: Use opaque IDs (UUIDs rather than sequential integers) that cannot be guessed or enumerated
- RBAC: Define roles with clear permissions, assign users to roles — avoid per-user permission grants that are difficult to audit
Testing
Access control testing must be part of every QA cycle — functional tests that verify a user cannot access another user's data, cannot call admin endpoints, and cannot escalate their own privileges.