Insecure Direct Object Reference

Insecure Direct Object Reference is when code accesses a restricted resource based on user input, but fails to verify user's authorization to access that resource. Put another way: there exists a "direct reference" to an "object" which is "insecure".

It is ranked as #4 on Top 10 security threats by OWASP.

It is easiest to understand Insecure Direct Object Reference by seeing an example and how it can be exploited.

Imagine that a user clicks on a link to view an invoice.

The code that accesses the invoice might look something like:

  $sql = "SELECT * FROM orders WHERE invoice_id='{$invoice}'";
  $result = myqli_query($connection, $sql);

This is the "direct object reference". A user has direct access to the invoice. The invoice ID goes directly into the SQL and returns the invoice. It is insecure because there is never any verification that the user is authorized to view the invoice. Not only could anyone use the same URL access this invoice, but entering other invoice IDs such as "TPX-10456" would most likely provide insecure access to other invoices. These invoices might reveal someone else's name, address, phone, email, credit card, items ordered, and more.

Examples of types resources which could have insecure direct references are:

  • Database data
  • Files
  • Directories
  • Scripts
  • Functions

If a user can trigger what should be a privileged result without having to validate their privileges, then it is probably a case of Insecure Direct Object Reference.

Insecure Direct Object Reference Preventions

The primary prevention is to validate a user's authorization before allowing access to a privileged resource. Require a user to log in, and confirm that logged in users have sufficient access privileges.

In some situations, it may be possible to whitelist the acceptable input and reject input which is not allowed.

Another prevention strategy is to change the direct object reference to an indirect object reference. One way would be to provide a user a list of choices which are specific to that user, which are meaningful only for that user's context.


  • Logged in user sees list of 4 previous orders
  • Previous orders are numbered 1-4
  • User chooses order #2
  • The request sends ID='2', not the order ID
  • ID is indirect, only meaningful in user's scope

In the above example, the only valid choices for the user are 1-4, all return resources for which the user is authorized. If another user attempts to access the same URL (with ID='2') it would only return one of their authorized resources.

Fork me on GitHub