Imagine a malicious hacker could access all your organization’s customer account details, or charge an online purchase to someone else’s credit card, just by changing a couple of digits in a URL. It sounds unlikely, but it’s precisely the kind of thing that a hacker can do if your Web applications are susceptible to an insecure direct object reference.
What is an insecure direct object reference?
The “objects” in question are internal implementation objects such as files, directories, database records or database keys, and a problem occurs when an application exposes a reference to one of these objects in a URL (or form parameter.) It’s a problem because a hacker can change these direct object references, for example by altering a URL before it is submitted, to attempt to access a different, unauthorized file, directory or database entry. This attempt may be successful unless some other authorization check is enforced.
Insecure direct object reference examples
Imagine a Web app that ends up generating the URL:
http://www.insecurewebapp.com/getfile.cfm?filename=sometextfile.txt
Here there is a very obvious direct reference to a file called “sometextfile.txt”, and the temptation for a hacker would be to see what happens when this filename is changed to some other filename, like “passwords.txt” or “accounts.txt”.
To succeed like this the hacker would have to correctly guess the name of another file on the system, but a more methodical approach would be to look for something specific elsewhere on the system, using a path traversal attack. Essentially this means accessing a completely different directory to the anything the developer of the vulnerable application intended. To access Apache Tomcat usernames and passwords, the hacker might alter the last part of the URL to “filename=../../tomcat/conf/tomcat-users.xml
Not all insecure direct object references provide access to files, or course. Another type of URL that would be a red rag to a hacker would be one that ended with:
…account.cfm?customerid=4566
which leads our hacker to next ask, “what happens if I modify this by changing the customerid to something like 4567?”
Similarly, what happens if a Web application allows a user to select a credit card from one or more stored in a database for that user, referenced by database key:
<select name="choosecreditcard"> <option value="35"> XXXXXXXXXXXX6002 </option> <option value="67"> XXXXXXXXXXXX1516 </option> </select>
and the hacker modifies the database key?
Here a user would be asked to select from one of two credit cards, ending 6002 and 1516, that the application has on file for them, referenced by their database key. In the resulting URL, a hacker would only have to change the 35 or 67 option value to another number, like 36, to reference some other credit card number, belonging to another user, stored with that database key. Unless, as mentioned at the start of this article, there are other authorization checks in force to prevent this, the attack could be successful.
Avoiding insecure direct object references
The best way to avoid insecure direct object reference vulnerabilities is not to expose private object references at all, but if they are used then it is important to ensure that any user is authorized before providing access to them. OWASP www.owasp.org recommends establishing a standard way of referring to application objects as follows:
- Avoid exposing your private object references to users whenever possible, such as primary keys or filenames
- Validate any private object references extensively with an “accept known good” approach. This means determining what files a user should be allowed to access, and only granting them access to those files
- Verify authorization to all referenced objects
An illustration, of this third point, also provided by OWASP, comes from a code sample in which a hacker could change an ecommerce cart ID parameter to any value:
int cartID = Integer.parseInt( request.getParameter( “cartID” ) );
String query = “SELECT * FROM table WHERE cartID=” + cartID;
This can be prevented by only allowing authorized records to be shown:
int cartID = Integer.parseInt( request.getParameter( "cartID" ) );
User user = (User)request.getSession().getAttribute( "user" );
String query = "SELECT * FROM table WHERE
cartID=" + cartID + " AND userID=" + user.getID();
An alternative to direct object references, which should be used whenever possible, is to use per user or session indirect object references.
In the example earlier a user was asked to select a credit card from a choice of two which exposed direct references to the database of credit cards. A better method would be to take the two credit card records and store them in an array specific to that user. The credit card selection box would be coded like this:
<select name=" choosecreditcard"> <option value="1"> XXXXXXXXXXXX6002 </option> <option value="2"> XXXXXXXXXXXX1516 </option> </select>
This way there is only a direct reference to an array for that user, containing only that user’s data. Changing the option value to a value greater than 2 would not result in any other user’s credit card details being used. The application would then map the user specific indirect object reference (option value=1 or option value=2) back to the underlying database key (35 or 67 in the example earlier.)
Testing for insecure direct object references
Unfortunately vulnerability scanners are not very effective at finding insecure direct object reference vulnerabilities, so the best options are:
- code reviews to identify whether important parameters are susceptible to manipulation
- penetration testing