advanced 2 min answer

Broken access control is consistently the top application security risk. Which architectural decisions make it structurally less likely rather than relying on review?

access-controlowaspstructureauthorisationsecurity
Show the full answer Hide the answer

What is being tested

Whether you can convert a recurring vulnerability class into structural properties, rather than proposing more training and more code review.

Why it stays the top risk

Because it is implemented per endpoint by whoever wrote it. Forty endpoints written by twelve people over three years produces forty independent chances to omit a check, and the omission is invisible — the endpoint works perfectly for the developer testing with their own account.

Code review does not reliably catch it because the missing check is an absence, and absences do not appear in diffs.

The structural decisions

1. Authorisation in a layer that cannot be bypassed. Data access goes through a component that requires the caller's identity as a parameter. Retrieving an object without an authorisation check becomes inexpressible rather than merely discouraged. This is the single highest-value change.

2. Object-level authorisation, not just endpoint-level. The canonical failure is GET /orders/{id} verifying the user is logged in but not that the order is theirs. Authorisation must be a function of (subject, action, object), and the object must be loaded through the authorised path.

3. Deny by default. A new endpoint is inaccessible until access is explicitly granted. Otherwise an endpoint is eventually deployed with no policy and discovered by a scanner.

4. Never trust network position. Anything reachable internally must still authenticate and authorise. The perimeter model — trusted inside, hostile outside — fails against exactly the scenario that matters, an attacker already inside, which is why per-request identity-based trust replaced it.

5. Non-enumerable identifiers. Sequential IDs let an attacker walk the dataset once they find one gap, and they leak business volume. Opaque identifiers reduce the impact of a single mistake.

6. Automated testing of the negative case. For every endpoint, an automated test that a different tenant's token receives a denial. Generated from the route table so a new endpoint without a test fails the build — this turns an absence into a build failure, which is the only reliable way to catch absences.

The tenancy version

For multi-tenant systems the strongest form is making tenant isolation a property of the data path: every query scoped by tenant automatically, through row-level security or a scoped repository, so a query without tenant scoping cannot be written. That is meaningfully stronger than remembering to add a WHERE tenant_id = ? clause forty times.

What a strong answer adds

Distinguishing authentication from authorisation, and noting where each belongs: authentication at the edge, coarse authorisation at the gateway, and fine-grained authorisation in the service that owns the resource — because only it knows the rules. Authorisation performed only at the gateway leaves everything reachable internally unprotected.