Insecure Direct Object Reference (IDOR) - Ravi-Upadhyay/cyber-security-playground GitHub Wiki
Index
Explanation
In simple words, if we take any kind of user input directly and use it in our queries to the database, it can lead to Insecure Direct Object Reference (IDOR). This happens because we missed checking the authorization of the user against the particular data.
Types of IDOR
- Horizontal IDOR: This occurs when an attacker or a valid user of the system is able to access data of other users by changing a parameter value. For example,
https://insecure-website.com/customer_account?customer_number=132355. - Vertical IDOR: This occurs when a user is able to access higher privileged information without proper authentication. For example, a regular user accessing admin functionalities.
- Indirect IDOR: This occurs when the reference to the object is indirect, such as through a secondary identifier, but still allows unauthorized access.
Access privilege escalations
- Horizontal privilege escalation: In this case, an attacker or valid user of the system is able to get the data of other customers by changing the
customer_number. - Vertical privilege escalation: If a user is able to access higher privileged information without proper authentication, it is known as vertical privilege escalation.
IDOR vulnerability with direct reference to static files
IDOR vulnerabilities often arise when sensitive resources are located in static files on the server-side filesystem. For example, a website might save chat message transcripts to disk using an incrementing filename, and allow users to retrieve these by visiting a URL like the following:
https://insecure-website.com/static/12144.txt
In this situation, an attacker can simply modify the filename to retrieve a transcript created by another user and potentially obtain user credentials and other sensitive data.
Risk Matrix
Exploitations
- Horizontal privilege escalation
- Vertical privilege escalation
- Password Leakage
- Bypassing Access Controls
- IDOR vulnerability with direct reference of static files
Fixes
- Application should have server-side authorization checks for each object request.
- Do not rely on security by obscurity.
- User/API interfaces should not refer to an internal object ID (e.g., name, file name, primary key).
- If you have to send any identifier to the frontend, it should be hashed using a SALT.
Code Snippets
For the complete example, you can visit Here
Java Example
import javax.xml.bind.DatatypeConverter;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* Handle the creation of ID that will be sent to the front end side
* in order to prevent IDOR
*/
public class IDORUtil {
/**
* SALT used for the generation of the HASH of the real item identifier
* in order to prevent forging it on the front end side.
*/
private static final String SALT = "[READ_IT_FROM_APP_CONFIGURATION]";
/**
* Compute an identifier that will be sent to the front end and be used as item
* unique identifier on the client side.
*
* @param realItemBackendIdentifier Identifier of the item on the backend storage
* (real identifier)
* @return A string representing the identifier to use
* @throws UnsupportedEncodingException If string's byte cannot be obtained
* @throws NoSuchAlgorithmException If the hashing algorithm used is not
* supported is not available
*/
public static String computeFrontEndIdentifier(String realItemBackendIdentifier)
throws NoSuchAlgorithmException, UnsupportedEncodingException {
String frontEndId = null;
if (realItemBackendIdentifier != null && !realItemBackendIdentifier.trim().isEmpty()) {
// Prefix the value with the SALT
String tmp = SALT + realItemBackendIdentifier;
// Get and configure message digester
// We use SHA1 here for the following reason even if SHA1 has now potential collision:
// 1. We do not store sensitive information, just technical ID
// 2. We want that the ID stay short but not guessable
// 3. We want that a maximum of backend storage support the algorithm used in order to compute it in selection query/request
// If your backend storage supports SHA256, use it instead of SHA1
MessageDigest digester = MessageDigest.getInstance("sha1");
// Compute the hash
byte[] hash = digester.digest(tmp.getBytes("utf-8"));
// Encode it in HEX
frontEndId = DatatypeConverter.printHexBinary(hash);
}
return frontEndId;
}
}
Node.js Example
const crypto = require('crypto');
/**
* Handle the creation of ID that will be sent to the front end side
* in order to prevent IDOR
*/
const SALT = process.env.SALT || '[READ_IT_FROM_APP_CONFIGURATION]';
/**
* Compute an identifier that will be sent to the front end and be used as item
* unique identifier on the client side.
*
* @param {string} realItemBackendIdentifier Identifier of the item on the backend storage
* (real identifier)
* @returns {string} A string representing the identifier to use
*/
function computeFrontEndIdentifier(realItemBackendIdentifier) {
if (!realItemBackendIdentifier || realItemBackendIdentifier.trim() === '') {
return null;
}
// Prefix the value with the SALT
const tmp = SALT + realItemBackendIdentifier;
// Compute the hash using SHA1
const hash = crypto.createHash('sha1').update(tmp, 'utf8').digest('hex');
return hash;
}
module.exports = { computeFrontEndIdentifier };
Resources Over Web
To do list
[ ] Integrate the OWASP example or lab activity