Session Fixation - Scala

Session Fixation - Scala

Need

Prevention of session hijacking

Context

  • Usage of Scala for building scalable and high-performance applications
  • Usage of play.api.mvc for handling HTTP requests and responses in the 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 SessionController @Inject()(cc: ControllerComponents) extends AbstractController(cc) {

  def login = Action { request =>
    val json = request.body.asJson.get
    val username = (json \\ "username").as[String]
    val password = (json \\ "password").as[String]

    if (isValidUser(username, password)) {
      Ok("Logged in").withSession("user" -> username)
    } else {
      Unauthorized("Invalid credentials")
    }
  }

  private def isValidUser(username: String, password: String): Boolean = {
    // Check the username and password against a database, etc.
    // This is just a placeholder for the example.
    true
  }
}
        
        

The above code represents a simple login function in a Scala backend application using the Play framework.

When a user attempts to login, the login action is called. This action retrieves the username and password from the request body and checks if they are valid using the isValidUser function. If the credentials are valid, the server responds with a "Logged in" message and sets a session cookie with the username. If the credentials are not valid, the server responds with an "Invalid credentials" message.

The vulnerability in this code is that the session cookie doesn't change after a valid login. This means that if an attacker knows a valid session cookie, they can set it in their own browser and hijack the user's session. This is known as Session Fixation.

In a Session Fixation attack, the attacker tricks the victim into using a session ID that the attacker knows. After the victim logs in, the attacker can use the same session ID to impersonate the victim. Because the session cookie doesn't change after login, the server can't distinguish between requests from the attacker and requests from the victim.

This is a serious security vulnerability because it allows an attacker to impersonate a user and potentially gain unauthorized access to sensitive information or perform actions on behalf of the user.

Steps

  • Generate a new session ID for each successful login
  • Invalidate the old session ID after generating a new one
  • Store the new session ID in a secure manner (e.g., encrypted)
  • Ensure that the session ID is not predictable or guessable
  • Implement session expiration to limit the lifetime of a session
  • Use secure cookies to store the session ID
  • Enable secure flag for cookies to ensure they are only sent over HTTPS
  • Implement proper session management and access control mechanisms
  • Regularly review and update session management code for any security vulnerabilities

Compliant code

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

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

  def login = Action { request =>
    val json = request.body.asJson.get
    val username = (json \\ "username").as[String]
    val password = (json \\ "password").as[String]

    if (isValidUser(username, password)) {
      val newSessionId = java.util.UUID.randomUUID.toString
      Ok("Logged in").withNewSession.withSession("user" -> username, "sessionId" -> newSessionId)
    } else {
      Unauthorized("Invalid credentials")
    }
  }

  private def isValidUser(username: String, password: String): Boolean = {
    // Check the username and password against a database, etc.
    // This is just a placeholder for the example.
    true
  }
}
        
        

The updated code now generates a new session ID for each successful login using java.util.UUID.randomUUID.toString. This session ID is unpredictable and not guessable, which helps to prevent session fixation attacks.

The old session is invalidated using .withNewSession before setting the new session data. This ensures that the old session data cannot be used for session hijacking.

The new session ID is stored in the session using .withSession("user" -> username, "sessionId" -> newSessionId). This ensures that the session ID is associated with the correct user.

Please note that this code does not implement all the recommended steps to prevent session fixation attacks. For example, it does not implement session expiration, secure cookies, or secure flag for cookies. These features may be implemented using the features of the Play framework or additional libraries.

Also, the isValidUser function is a placeholder and should be replaced with actual code to validate the username and password against a database or other user store.

References