This tutorial aims to teach you about Insecure Direct Object References (IDOR), a common vulnerability in web applications, and how to secure your applications against it.
By the end of this tutorial, you will understand what IDOR is, why it is a severe security risk, and the best practices to prevent it in your web applications.
Before you start, you should have a basic understanding of web development, particularly in server-side technologies like PHP, Node.js, or Java. Familiarity with SQL and database management is also helpful.
IDOR occurs when a web application exposes a reference to an internal implementation object. Attackers can manipulate these references to access unauthorized data.
For example, consider an URL like http://example.com/app/accountInfo?acc=1234
. Here, 1234
is a direct object reference. If an attacker changes it to 1235
, they might access someone else's account data.
The best way to prevent IDOR is to use indirect object references. Instead of exposing actual identifiers (like account numbers or primary keys), use other identifiers that are mapped to actual data but meaningless outside the application.
// Direct Reference
$accountNumber = $_GET['acc'];
$query = "SELECT * FROM accounts WHERE acc_num = '$accountNumber'";
// Indirect Reference
$sessionAccNumber = $_SESSION['acc_num'];
$query = "SELECT * FROM accounts WHERE acc_num = '$sessionAccNumber'";
In the first example, the account number is taken directly from the URL, making it vulnerable to IDOR. In the second example, we use a session variable to reference the account. An attacker can't manipulate this reference easily.
We've learned about IDOR vulnerabilities and how they can allow unauthorized data access. We've also discussed how indirect object references can secure your application against IDOR. Always remember to validate user inputs and implement proper access controls.
Imagine you're building a blog platform. Users should only be able to edit their own posts. Write a function that checks if the current user is the author of the post they're trying to edit.
Convert the following direct object reference to an indirect one:
$userId = $_GET['user_id'];
$query = "SELECT * FROM users WHERE user_id = '$userId'";
function canEditPost($userId, $postId) {
// Query to find the author of the post
$query = "SELECT author_id FROM posts WHERE post_id = '$postId'";
// If the logged-in user is the author, return true
if ($userId == $query) {
return true;
}
// If not, return false
return false;
}
Here, we're checking if the current user is the author of the post. If they are, they can edit the post. If not, they can't.
$sessionUserId = $_SESSION['user_id'];
$query = "SELECT * FROM users WHERE user_id = '$sessionUserId'";
Instead of taking the user ID directly from the URL, we're using a session variable. This is an indirect object reference and is much more secure.