Skip navigation to main content

OWASP : Insecure Direct Object References

This is the fourth in a series of posts on the OWASP Top Ten

IDOR is a special form of Injection Attack. In an Injection Attack, the attacker is getting the server to run arbitrary commands on its own behalf; commands which may have little or no relation to the intended command. With an IDOR command, the attacker is injecting a value that is syntactically correct (i.e. escaping or input sanitisation pass) but in context, the attacker does not have 'permission' to access the data associated with their injected value.

Smarter Banking

Let's imagine that that a web application has been developed that allows users to login and view statements for several credit cards they might own. On our Statement Page there is a form which allows us to select our each card from a dropdown list. Under the hood, when the form is submitted to the server, an internal reference to our credit card is sent through to our application…

Function getStatement(accountID){
  cleanAccountID = toInt(accountID);
  if(cleanAccountID <0){
    throw error("Injection Attack!!")
  }
  sqlGetStatement = "SELECT * FROM Statements WHERE accountID = " + cleanAccountID
  statement = Sql.execute(sqlGetStatement)
  Return statement
}

So we're neatly checking to make sure that the input (accountID) is actually a integer and is therefore syntactically correct for inclusion in our SQL command. This avoids the injection attack vector, however, we are not validating that the logged in user owns the account being targeted. So if I were logged in and I happened to inject the accountID for an account that was not mine, this function would still return the statement for that account. Yikes!

To prevent this, we need to add some context awareness to our function. We need to make it so that it filters out only those accounts our user has permission to access. We could rely on our cookie variables to help us?

Function getStatement(accountID){
  cleanAccountID = toInt(accountID);
  if(cleanAccountID <= 0){
    throw error("Injection Attack!!")
  }
  sqlGetStatement = "SELECT * FROM Statements WHERE accountID = " + cleanAccountID + " AND userID = " + cookie.getParameter("LoggedInUserID")
  statement = Sql.execute(sqlGetStatement)
  if(IsEmpty(statement)){
    throw error("IDOR Attack!!")
  }
  return statement
}

So now we're validating that the logged in user is the owner of the account being targeted. Obviously if they've had their cookie stolen or there are concerns over the implementation of the authentication system, then this is all rather moot. But in principle this is quite an easy vulnerability to plug, although it needs careful architectural design to include a permission based system to help enforce contextual access to sensitive data across the entire application.

Distrust your users!

With input sanitisation (our cure for injection attacks) this is quite easy to include architecturally into our application such that all user input is sanitised. But to protect our application from IDOR attacks, our developers and architects will need a clear appreciation of where sensitive data is referenced via user input, and to integrate a context-aware access model for that data.

Next Time : Security Misconfiguration

 

Join the conversation on Twitter: @OWASP   #OWASPtop10   #IDOR