A01: Broken Access Control
Chapter Eighty-Four
Syllabus topic Module 2, "Web Application Threats and OWASP Vulnerabilities: Examine major web application vulnerabilities (OWASP Top 10)"
Pages 395 to 398 of 578
In one line
Broken access control is users being able to do things they should not: read another user's data, reach an administrative function, or act beyond their role. It is the most common serious web-application weakness, and it happens because applications check who you are (authentication) and forget to check what you may do (authorisation).
In examination wording: broken access control is the failure to enforce restrictions on what authenticated users are permitted to do, allowing access to unauthorised functionality or data; it encompasses insecure direct object references, missing function-level authorisation, and privilege escalation, and it is remedied by enforcing authorisation server-side on every request against the acting user's permissions.
Authentication against authorisation
The distinction is the key to the whole category, so state it precisely.
- Authentication answers "who are you?". It is the login: verifying identity.
- Authorisation (access control) answers "what are you allowed to do?". It is the check, on each action, that this identity is permitted this operation on this resource.
They are different, and applications routinely get the first right and the second wrong: a user logs in correctly (authentication works), and then the application fails to check, on each request, that they may do what they are asking (authorisation fails). Because logging in feels like the security step, the per-request authorisation check is forgotten, which is exactly why this category is the most common.
The rule the category enforces: being logged in is not permission to do anything; every action must be authorised against the acting user's permissions.
The forms it takes
Insecure direct object references. The application exposes a reference to an object (a record, a file, an account) and acts on it without checking the user is allowed that object. The classic case: a page shows your account statement at an address containing your account number, and changing the number to another account's shows their statement, because the application returned the record named in the request without checking it belonged to the requester. This is horizontal access control failing (the horizontal-escalation idea from the system-hacking block), and it is extremely common.
Missing function-level access control. An administrative or privileged function is protected only by not being linked for ordinary users, rather than by an actual check. An ordinary user who discovers or guesses the address of the admin function can use it, because the application never verifies that the caller is an administrator; it merely did not show them the link. Hiding a function is not protecting it, exactly as the search-engine reconnaissance chapter said hiding a page is not protecting it.
Privilege escalation through access control. A user manipulates a request (a role in a cookie, a parameter, the previous chapter's cookie manipulation) to gain higher privileges, because the application trusts client-supplied data about what the user may do.
A01: Broken Access Control
Metadata and method manipulation. Changing the HTTP method, or other request metadata, to reach an operation the application authorises for one method but not another.
Forced browsing. Directly requesting resources or functions the user was never meant to reach, which succeeds when authorisation is not enforced on them.
Why it is the most common category
Three reasons a student should be able to give, because they explain the category's persistence:
- Authorisation is per-action, so it is easy to miss one. A large application has hundreds of actions, each needing an authorisation check, and missing the check on any one is a vulnerability. Authentication is one place; authorisation is everywhere, so it is more often incomplete.
- The default is often "allow". Where authorisation is not enforced, the action frequently proceeds, so a forgotten check fails open. Secure design makes the default "deny", so a forgotten check fails closed.
- It is invisible in normal use. A user testing their own account never triggers the flaw, because they are accessing their own data; it only appears when someone accesses someone else's, which ordinary testing does not do. So the flaw ships undetected, which is why it is so common in production.
The defences
The fixes follow from the authentication-authorisation distinction:
Enforce authorisation on every request, server-side. Every action that touches a resource checks, on the server, that the acting user is permitted this operation on this specific resource. Not once at login, not in the browser, but on each request, on the server. This is the primary fix and it removes most of the category.
Deny by default. Design so that access is refused unless explicitly granted, so a forgotten check fails closed rather than open. This turns the "default allow" weakness into a "default deny" strength.
Do not rely on hiding. A function or resource is protected by an authorisation check, never by being unlinked or having an unguessable address. Hiding is not access control.
Use indirect references or verify ownership. Either do not expose direct object references (use identifiers that are looked up against the user's own resources), or, where a reference is exposed, verify on every access that the resource belongs to the requester. This closes insecure direct object references.
Do not trust client-supplied authorisation data. The user's role and permissions are held and checked server-side, never taken from a cookie or parameter (the cookie-manipulation fix), which closes the escalation-through-manipulation form.
Test for it deliberately. Because it is invisible in normal use, testing must specifically attempt to access other users' resources and privileged functions, with multiple test accounts, which is exactly what the flaw's invisibility requires.
A01: Broken Access Control
A worked example, framed defensively
An assessor tests an application for broken access control, using two test accounts they control.
- Logged in as test user A, changing an
account_idin a URL to test user B's returns B's statement. Insecure direct object reference / broken access control: the application checked A was logged in but not that the account was A's. Fix: verify on every access that the account belongs to the acting user. - The address of an admin page is guessed; as an ordinary user, it loads and functions. Missing function-level access control: the function was hidden, not protected. Fix: enforce an administrator check on the function server-side.
- A role in a cookie can be changed to elevate privileges. Privilege escalation through manipulation: the application trusts client data about the role. Fix: hold the role server-side.
- The assessor confirms the fixes by attempting the same accesses and finding them refused with a proper authorisation error.
The report leads with this category because it is the most common and most serious, and the assessor establishes each finding by accessing resources between their own two test accounts, never a real user's data, which is the minimum and the ethical way to prove it.
What beginners get wrong
- Confusing authentication with authorisation. Authentication is who you are; authorisation is what you may do. This category is authorisation failing after authentication succeeds.
- Thinking being logged in is permission. Every action must be authorised against the acting user's permissions, on the server, on each request.
- Protecting functions by hiding them. An unlinked or unguessable address is not access control; enforce a check.
- Trusting client-supplied role or permission data. Hold and check them server-side; a role in a cookie can be changed.
- Testing only your own account. The flaw is invisible in normal use; testing must attempt to reach other users' resources with multiple accounts.
- Failing open. Where authorisation is not enforced the action often proceeds; design to deny by default so a forgotten check fails closed.
Quick revision
- Broken access control = users doing what they should not (read others' data, reach admin functions, exceed their role); the most common serious web-application weakness, leading both OWASP editions.
- The key distinction: authentication (who you are) against authorisation (what you may do). The category is authorisation failing after authentication succeeds.
- Forms: insecure direct object references (act on a referenced object without checking ownership), missing function-level control (hidden, not protected, functions), privilege escalation (manipulating role/permission data), method manipulation, forced browsing.
- Common because authorisation is per-action (easy to miss one), often fails open, and is invisible in normal use (you test your own account).
- Defences: enforce authorisation server-side on every request against the acting user; deny by default; do not rely on hiding; verify ownership or use indirect references; hold roles server-side; test deliberately with multiple accounts.
A01: Broken Access Control
Test yourself
- What is the difference between authentication and authorisation, and how does this category relate to it?
Authentication answers "who are you?", verifying identity at login, while authorisation answers "what are you allowed to do?", checking on each action that the identity is permitted the operation on the resource. Broken access control is the category in which authentication succeeds but authorisation fails: the user logs in correctly, and the application then fails to check, on each request, that they may do what they are asking.
- What is an insecure direct object reference?
It is when an application exposes a reference to an object, such as a record or account identifier, and acts on it without checking that the requesting user is allowed that object, so changing the reference in a request, for example another account's number in a URL, returns that other object. It is a failure of horizontal access control and one of the most common forms of the category.
- Why is protecting a function only by not linking it inadequate?
Because not linking a function hides it but does not protect it: an ordinary user who discovers or guesses the function's address can invoke it, since the application never verifies that the caller is authorised for it. Access control must be an enforced server-side check on the function, not the mere absence of a visible link, exactly as hiding a page does not make it private.
- Why is broken access control the most common serious web-application category?
Because authorisation must be enforced on every one of an application's many actions, so missing the check on any single action is a vulnerability, whereas authentication is one place; because it often fails open, proceeding when the check is absent; and because it is invisible in normal use, since a user accessing their own account never triggers it, so it ships to production undetected by ordinary testing.
- What is the primary defence, and why must access control be tested deliberately?
The primary defence is to enforce authorisation on every request, on the server, checking that the acting user is permitted the specific operation on the specific resource, with a deny-by-default design so a forgotten check fails closed. It must be tested deliberately because the flaw does not appear when a user accesses their own resources, so testing must specifically attempt to reach other users' data and privileged functions using multiple test accounts.
The rest of this subject
These notes are cut from the University's printed syllabus. Open the syllabus itself for the same subject.