> Hello, I'm user number fiftysev.... Fiftyeight.
Insecure Direct Object References are types of authorization issues, where a user can access information (objects) which they are not supposed to.
For example, imagine a bank application where you can view your personal info via:
Now, what does "57" refer to? Probably some kind of reference to your user account. A... Direct... Reference... To your user account.
So the application probably runs a database query like:
SELECT * from profiles where userid = ?
So what happens if you swap 57 to something else? 58? Or perhaps 56 because, you reason, it is probably guaranteed to exist a user with the previous ID if it's an incrementing counter.
If the application allows you to view profiles of other users (perhaps including their bank details and balances), the application has an issue with A4, as it exposes a direct reference to an object, and does not properly check if whoever queries it is authorised to get access to the data.
What to look out for
Again, this is a set of authorisation-problems. Exposing references and identifiers is never a good thing to do, but it's not a vulnerability in itself as long as proper access control is in place.
Now, you could go through the following mental checklist in order to check for A4:
A. Does this page always look the same, for all people and under all circumstances?
If not, chances are the application presents different pages depending on some user input.
B. How are the unique/dynamic pages identified?
Look at the HTTP request. Are you sending some kind of token or identifier to indicate what page you want? Is it tied to the session/login?
Make sure to look at:
- GET-parameters, e.g. "?id=57§ion=all"
- POST-parameters (request body)
- Cookies (delete one of them at a time, and see if the page changes)
- Common headers (do you get the mobile site if you pretend to be on iOS?)
- Other headers (custom headers?)
C. What is the scope of this identifier?
Let's say you find "?id=57". What is the scope? For user profiles... Probably site-wide. An id represents a user globally throughout the application.
Though what if you see "transactions.php?acc=2"? Perhaps that displays the transactions for account number two. Since there are probably thousands of bank accounts in the system, the scope of this identifier is probably bound to your account.
It's terribly important to recognise that identifiers have a scope in which they are valid. Something that is not unique can only be successfully used in certain contexts, i.e. I could have 100 accounts, but you may only have 3.
From this, you can start to guess (and draft) how the application handles the identifier for the object. Perhaps something is used to set the context, which can be exploited. Perhaps you can change context somehow.
D. Is it possible to access other objects from this control? Should that be allowed?
Swap one reference for another. What happens in the following cases:
1. Use the reference given by the application. This is the default request and should work.
2. Swap to another reference "owned"/associated with your current user account. Most of the time this works as well. If it doesn't, then we learn something about in which context/scope we can use it... Perhaps there is something else that needs to match up?
3. Refer to an object owned by another user account (might require you to have another account). This will work a lot of the time, you'd be surprised (or not, since it's on the OWASP top 10 list...)
4. Refer to an object that does not exist. Most of the time this will yield a generic error, though verbose stack traces are also possible.
Some users should be able to view the data of others, keep that in mind when testing. Users should not be able to read private messages belonging to others, but perhaps administrators should be allowed to do so.
For existing applications, make sure to implement access restrictions for all objects. User A should only be able to fetch resources that user A is allowed to view, and so on. Identify all references within the application, implement the necessary checks, and make sure to test it.
For new applications, consider avoiding these references altogether. Do you need to pass the user ID, if the user is already logged in? Do you need to have global references, or could they be references to the specific objects belonging to the current user only? Would you be able to present dummy references and then re-map them to the internal references later on?
Make sure to double-check that the user is permitted to access whatever they're trying to access. If not, it might be possible to access other users data by directly modifying the exposed references.