Broken Access Control
Broken access control lets a caller access resources or perform actions outside the permissions granted to them. Prevent it with server-side, resource-specific authorization checks that fail closed and cover every access path.
Broken access control occurs when an application does not correctly enforce permissions for an authenticated or anonymous caller. The result may be unauthorized reading, modification, deletion, or execution of an operation.
Typical causes include trusting a user-supplied role, checking permissions only in the frontend, missing authorization on one endpoint, or verifying that a user is logged in without checking resource ownership. An attacker may exploit this by changing an object ID, HTTP method, account identifier, or administrative route.
Authorization checks should run on the server for every protected operation. They should evaluate the current identity, the requested action, the target resource, and the applicable policy; for example, a user may read only their own document while an administrator may read all documents.
In a Python backend, centralize authorization policy where practical, fail closed when identity or permission data is missing, and test both allowed and denied cases. Avoid leaking sensitive details through error responses, while still returning an appropriate status such as `401` for missing authentication and `403` for an authenticated caller without permission.
Key points
- Enforce authorization on the server for every protected action.
- Check permissions against the actual target resource, not just the URL or supplied role.
- Use least privilege and deny by default when no rule grants access.
- Test unauthorized object access, alternate endpoints, bulk actions, and different HTTP methods.
- Distinguish missing authentication (`401`) from insufficient permission (`403`) where appropriate.
Interview questions
What is the difference between authentication and authorization?
Authentication identifies the caller, such as by validating a session or token. Authorization evaluates whether that identified caller can perform a specific action on a specific resource. A user can be authenticated and still be forbidden from deleting another user's record. The decision belongs on the server because client-side checks can be bypassed.
How would you protect an endpoint that returns a document by ID?
I would identify the current user from trusted server-side authentication data, load the target document, and compare its owner or permitted principals with the requested action. The check must happen before returning or modifying the document. I would also test a valid owner, another regular user, an administrator if applicable, a missing document, and an unauthenticated request. The policy should be centralized or consistently reused so one endpoint cannot accidentally omit it.
What is an IDOR-style access-control flaw, and how would you find it?
I would treat every client-controlled identifier as untrusted and verify object-level permission after resolving the resource. A request such as `/users/7/orders/42` must not be authorized merely because the path contains a plausible user ID; the authenticated principal and order relationship must be checked. I would also look for alternate endpoints, bulk operations, export jobs, and different HTTP methods that expose the same data. Automated authorization tests and centralized policy code help prevent regressions.
How would you design a robust authorization system for a multi-tenant Python backend?
I would model authorization as a policy over subject, action, resource, and context, rather than scattering role checks throughout handlers. The policy should support least privilege, deny by default, and make tenant boundaries explicit. I would enforce it at service boundaries, constrain database queries where possible, and separately protect asynchronous workers, object storage, and administrative APIs. I would validate the design with threat modeling, negative tests, audit logs, and monitoring for repeated denied access.