A Direct Object Reference security breach occurs when a user changes an id, usually within a url (or perhaps a hidden field) and suddenly sees information (or performs an action) that he or she is not supposed to be able to do. So a the url had in it “order=1″ and a user changes it to “order=2″ hopefully the website will check if the user is allowed to see order 2 and if not prevent the user from viewing someone else’s information.
This Direct Object Reference should be thought of both in terms of permission to access the record and also importantly the state of the record. One major difference between writing a thick client and web application is that the user can generally type in whatever they want in the url to perform an action i.e. /order/edit/1. What if record 1 is a closed order? This is very different to a thick client where access to functions can be controlled tightly from the previous screen.
Generally access to a controller can be controlled via authorise attributes such as follows
This attribute should be set either on the controller or on the actions within the controller. The Authorize attribute forces the user to Authenticate (login) and then also Authorizes (checks) that the user is allowed access to the controller or action depending on their role.
The Direct Object Reference issue arises when more control to access or alter information is required. The types of checks that need considered are below:
- What if I want to look at a order? – presumably I should only be able to see the orders I have created and not orders that belong to other users. This is really a more indepth authorization check.
- What if I want to edit an order that has been fulfilled? – this is really a state\business rule issue.
These sorts of bugs are very common and easily introduced. A user simply changes an id in a url and bingo sees someone else’s personal information.
The best defence is basic thought process when creating an action. Two layers of checks should be added in the code. The first makes sure the user is allowed to see the information in the first place. The second checks the state of the record or other business rules. An example is shown below
[Authorize(Roles = “Admin, Super User”)]
public ActionResult MyOrder(int id)
//// First check if the user is allowed to see the record. the method below should check against the database that the user is the owner of the order being accessed and if not throw an exception, return a 401 or do something to prevent access
//// Second check the order is in the correct status for the action, perhaps in this case only orders that are in the state “open” can be accessed via MyOrder, if not open throw an exception, return a 401 or do something to prevent access
//// now get order and return the correct view
A pattern like this is a good approach. If the layers of checks are not required the developer should add a comment to state this, then at least you know they have thought about it.
Your specs and design documents should probably also state these sort of rules per action. This makes developing and writing test scripts easier to write.
The pattern for an update is much the same, only before checking authorization and business rules you probably want to check the model is valid
The approach you use may depend on how your solution is structured. Perhaps your business rules are in the back end and not in a controller. The point is not where the rules are added but that business analysts add these rules to documents as standard and developers consider theses as standard i.e. it becomes ingrained in the culture to think about this and then everyone agrees how and where the rules are added.
Note adding this type of functionality at the time of development does not take that long, having to retrofit it is a lot more expensive.