Skip to main content

Insecure object reference - Personal information

Need

Secure access control and user authorization

Context

  • Usage of Java for building scalable and robust applications
  • Usage of javax.servlet-api for building Java web applications with Servlets
  • Usage of java.io for input and output operations in Java programming

Description

Non compliant code

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class UserController {

private UserRepository userRepository;

public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
String id = request.getParameter("id");
String name = request.getParameter("name");
String email = request.getParameter("email");

User user = userRepository.findUserById(id);
user.setName(name);
user.setEmail(email);

userRepository.updateUser(user);
}
}

In the given code, the system retrieves the user's unique identifier (ID) from the request parameters. This ID is then used to find the corresponding user and update their information. This code is vulnerable to insecure direct object reference (IDOR) attacks because it trusts user input without any validation or authorization checks.

An attacker can exploit this vulnerability by manipulating the 'id' parameter in the HTTP request to reference objects they are not supposed to access. For example, an attacker could change the 'id' parameter to another user's ID to update their information, thereby bypassing the authentication mechanism.

The vulnerability lies in the doPost method of the UserController class. The method retrieves the 'id', 'name', and 'email' parameters from the HTTP request without any validation:

String id = request.getParameter("id");
String name = request.getParameter("name");
String email = request.getParameter("email");

Then it uses the 'id' to find the user:

User user = userRepository.findUserById(id);

And then it updates the user's name and email:

user.setName(name);
user.setEmail(email);
userRepository.updateUser(user);

In this process, there's no check to ensure that the user making the request is authorized to update the information of the user specified by the 'id'. This makes it vulnerable to IDOR attacks.

Steps

  • Implement proper authentication and authorization mechanisms to ensure that only authorized users can access and modify user information.
  • Do not rely solely on client-side input validation. Implement server-side input validation to prevent malicious input.
  • Use a secure session management mechanism to ensure that each user's session is properly authenticated and authorized.
  • Avoid using user-provided input directly as identifiers or keys for accessing and modifying sensitive data.
  • Instead, use a separate, internal identifier or key that is not exposed to the user and cannot be manipulated.
  • Implement access controls and validation checks to ensure that a user can only modify their own information and not others'.
  • Regularly update and patch the system to fix any known vulnerabilities and security issues.
  • Conduct regular security audits and penetration testing to identify and address any potential vulnerabilities in the system.

Compliant code

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.Principal;

public class UserController {

private UserRepository userRepository;

public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}

protected void doPost(HttpServletRequest request, HttpServletResponse response, Principal principal) throws IOException {
String name = request.getParameter("name");
String email = request.getParameter("email");

User currentUser = userRepository.findUserByUsername(principal.getName());

if(currentUser != null){
currentUser.setName(name);
currentUser.setEmail(email);
userRepository.updateUser(currentUser);
} else {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized access");
}
}
}

The updated code now includes proper authentication and authorization mechanisms to ensure that only authorized users can access and modify user information.

The doPost method now takes an additional parameter, Principal principal, which represents the currently authenticated user. The Principal object is provided by the security context of the servlet container and contains the username of the authenticated user.

Instead of getting the user ID from the request parameters (which can be manipulated by the client), the code now gets the username from the Principal object and uses it to look up the corresponding User object from the UserRepository. This ensures that the user can only modify their own information and not others'.

If the User object corresponding to the authenticated user is found, the code updates the user's name and email as before. If the User object is not found (which means that the user is not authenticated), the code sends an HTTP 401 Unauthorized error response.

This approach avoids using user-provided input directly as identifiers or keys for accessing and modifying sensitive data, and instead uses a separate, internal identifier (the username) that is not exposed to the user and cannot be manipulated.

In addition to these changes, it is recommended to implement server-side input validation to prevent malicious input, use a secure session management mechanism, regularly update and patch the system, and conduct regular security audits and penetration testing.

References