Insecure object reference - Files - Scala

Insecure object reference - Files - Scala

Need

Secure and controlled access to user files

Context

  • Usage of Scala for building scalable and high-performance applications
  • Usage of play.api.mvc for handling HTTP requests and building web applications in Play Framework
  • Usage of play.api.libs.json for JSON parsing and manipulation in Play Framework

Description

Non compliant code

        import play.api.mvc._
import play.api.libs.json._

class UserController @Inject()(cc: ControllerComponents) extends AbstractController(cc) {

  def getUserData(userId: String) = Action { implicit request: Request[AnyContent] =>
    val user = User.find(userId)
    user match {
      case Some(u) => Ok(Json.toJson(u))
      case None => NotFound
    }
  }
}
        
        

The getUserData function in the UserController class is vulnerable to Insecure Direct Object References (IDOR) vulnerability. This function takes a userId as a parameter, retrieves the user information from the database, and returns it as a JSON object.

The issue here is that there is no authorization check to verify if the user requesting the data is allowed to access it. This means that if an attacker knows or guesses the userId of another user, they can access or manipulate their data. This is because the userId is directly used to fetch the user data from the database without any additional access control checks.

The lack of proper access control checks can lead to unauthorized information disclosure, data tampering, and other security issues, making the system vulnerable to IDOR attacks.

This vulnerability can be exploited by an attacker by simply sending a GET request to the getUserData endpoint with the userId of the user whose data they want to access or manipulate.

Steps

  • Implement proper authentication and authorization mechanisms to ensure that only authorized users can access the getUserData endpoint.
  • Validate the user's permissions before retrieving and returning the user data.
  • Use session management or tokens to securely identify and authenticate users.
  • Implement access control checks to ensure that users can only access their own data.
  • Consider implementing role-based access control (RBAC) to manage user permissions.
  • Regularly review and update the access control mechanisms to address any potential vulnerabilities.

Compliant code

        import play.api.mvc._
import play.api.libs.json._

class UserController @Inject()(cc: ControllerComponents, authAction: AuthenticatedAction) extends AbstractController(cc) {

  def getUserData(userId: String) = authAction { implicit request: Request[AnyContent] =>
    val loggedInUser = request.user
    if(loggedInUser.id == userId) {
      val user = User.find(userId)
      user match {
        case Some(u) => Ok(Json.toJson(u))
        case None => NotFound
      }
    } else {
      Unauthorized
    }
  }
}
        
        

The updated code now includes an authAction which is an instance of AuthenticatedAction. This is a custom action builder that checks if a user is authenticated before the action is executed. If the user is not authenticated, it will return an Unauthorized result.

In the getUserData method, we first retrieve the logged-in user from the request. This user is set in the AuthenticatedAction after successful authentication.

Next, we check if the logged-in user's id matches the userId parameter. If it does, we proceed to find the user and return the user data. If it doesn't, we return an Unauthorized result. This ensures that users can only access their own data.

This approach effectively mitigates the insecure direct object reference vulnerability by implementing proper authentication and authorization checks. It ensures that only authenticated and authorized users can access the getUserData endpoint.

References