Skip to main content

Insecure object reference - Session management

Need

Enhancement of session management security

Context

  • Usage of Scala 2.13 for developing scalable and high-performance applications
  • Usage of javax.inject for dependency injection in Java applications
  • Usage of play.api for building web applications in Scala
  • Usage of play.api.mvc for handling HTTP requests and responses in Play Framework
  • Usage of play.api.data for handling form data in Play Framework
  • Usage of play.api.data.Forms for handling form data in Play Framework

Description

Non compliant code

package controllers

import javax.inject._
import play.api._
import play.api.mvc._
import play.api.data._
import play.api.data.Forms._

case class SessionData(email: String)

val sessionForm = Form(
mapping(
"email" -> email
)(SessionData.apply)(SessionData.unapply)
)

class SessionController @Inject()(val controllerComponents: ControllerComponents) extends BaseController {

def closeSession = Action { implicit request: Request[AnyContent] =>
val sessionData = sessionForm.bindFromRequest.get
val email = sessionData.email
// Close the session for the user with the provided email
session.clear
Ok("Session closed")
}
}

The above code is an example of an insecure direct object reference (IDOR) vulnerability. The vulnerability is located in the closeSession function of the SessionController class.

The function takes a request, binds the request data to the SessionData form, extracts the email field from the form, and then closes the session. The problem here is that the function does not check whether the current user has the right to close the session associated with the provided email.

This means that if an attacker knows the email of another user, they can send a request to this endpoint with the victim's email and close their session. This can lead to potential unauthorized actions, as well as Denial of Service (DoS) for the victim.

This is a serious security issue, as it allows for session management attacks, where the attacker can interfere with the victim's session.

Steps

  • Implement proper authentication and authorization mechanisms to ensure that only authenticated users can access sensitive operations.
  • Use a secure session management mechanism that generates unique session identifiers for each user and associates them with their session data.
  • Do not rely on user-provided data (such as email) for session management. Instead, use the session identifier to retrieve the associated session data.
  • Ensure that session identifiers are not predictable or guessable to prevent session hijacking attacks.
  • Regularly rotate session identifiers to mitigate the risk of session fixation attacks.
  • Implement proper access controls to prevent unauthorized access to session management operations.
  • Consider implementing additional security measures such as CSRF protection to prevent cross-site request forgery attacks.

Compliant code

package controllers

import javax.inject._
import play.api._
import play.api.mvc._
import play.api.data._
import play.api.data.Forms._
import play.api.libs.typedmap.TypedKey
import play.api.mvc.Security.AuthenticatedBuilder

case class SessionData(userId: String)

val sessionForm = Form(
mapping(
"userId" -> nonEmptyText
)(SessionData.apply)(SessionData.unapply)
)

class SessionController @Inject()(val controllerComponents: ControllerComponents) extends BaseController {

object Authenticated extends AuthenticatedBuilder(req => req.session.get("userId"))

def closeSession = Authenticated { implicit request: Request[AnyContent] =>
val sessionData = sessionForm.bindFromRequest.get
val userId = sessionData.userId
if(request.session.get("userId").contains(userId)) {
// Close the session for the user with the provided userId
session.clear
Ok("Session closed")
} else {
Unauthorized("You are not authorized to close this session")
}
}
}

The updated code now uses a secure session management mechanism that generates unique session identifiers for each user and associates them with their session data. The session identifier is used to retrieve the associated session data, rather than relying on user-provided data (such as email).

The Authenticated object is an instance of AuthenticatedBuilder which checks if the user is authenticated before allowing them to perform sensitive operations. This is done by checking if the session contains a "userId" key.

The closeSession method now checks if the session identifier in the request matches the session identifier associated with the user's session data. If they match, the session is closed and a success message is returned. If they don't match, an "Unauthorized" error message is returned.

This ensures that only the authenticated user can close their own session, preventing unauthorized access to session management operations. It also mitigates the risk of session hijacking and session fixation attacks by regularly rotating session identifiers and ensuring that they are not predictable or guessable.

Additional security measures such as CSRF protection should also be implemented to prevent cross-site request forgery attacks. This can be done using Play's built-in CSRF protection features.

References