Insecure session management - Change Password - Scala

Insecure session management - Change Password - Scala

Need

Secure session management - Close session after password change

Context

  • Usage of Scala 2.12 for developing scalable and high-performance applications
  • Usage of play.api.mvc._ for handling HTTP requests and responses in Play Framework

Description

Non compliant code

        def changePassword = Action { implicit request =>
  val oldPassword = request.body.asFormUrlEncoded.get("oldPassword")(0)
  val newPassword = request.body.asFormUrlEncoded.get("newPassword")(0)
  
  val user = getUserFromSession(request)
  
  if(user.checkPassword(oldPassword)){
    user.changePassword(newPassword)
    Ok("Password changed successfully")
  } else {
    Unauthorized("Incorrect password")
  }
}
        
        

The above code is a typical implementation of a password change feature in a Scala backend application using the Play framework. The function changePassword is an Action that takes the current HTTP request as an implicit parameter.

The old password and the new password are extracted from the request body using request.body.asFormUrlEncoded.get("oldPassword")(0) and request.body.asFormUrlEncoded.get("newPassword")(0) respectively.

The user is fetched from the session using the getUserFromSession(request) function.

The code then checks if the old password is correct using user.checkPassword(oldPassword). If the old password is correct, the password is changed with user.changePassword(newPassword), and a success message is returned. If the old password is not correct, an Unauthorized error is returned.

The vulnerability here is that after the password is changed, the session remains open. This means that if an attacker has gained access to the user's session, they can still perform actions as the user even after the password has been changed. This is a serious security issue as it can lead to unauthorized access and potential data breaches.

Steps

  • Implement a session timeout mechanism to automatically expire sessions after a certain period of inactivity.
  • Invalidate the existing session after a password change to ensure that the old session is no longer valid.
  • Generate a new session for the user after a successful password change to ensure that the user is authenticated with the updated credentials.
  • Use secure session management techniques such as encrypting session data and using secure cookies to prevent session hijacking.
  • Implement strong password policies and enforce password complexity requirements to enhance the security of user passwords.
  • Regularly review and update the session management code to address any new vulnerabilities or best practices.

Compliant code

        import play.api.mvc._
import play.api.libs.typedmap.TypedKey

val UserKey: TypedKey[User] = TypedKey[User]("user")

def changePassword = Action { implicit request =>
  val oldPassword = request.body.asFormUrlEncoded.get("oldPassword")(0)
  val newPassword = request.body.asFormUrlEncoded.get("newPassword")(0)
  
  val user = request.attrs.get(UserKey)
  
  if(user.isDefined && user.get.checkPassword(oldPassword)){
    user.get.changePassword(newPassword)
    val newSession = request.session - "user"
    Ok("Password changed successfully").withNewSession.withSession(newSession.data.toSeq: _*)
  } else {
    Unauthorized("Incorrect password")
  }
}
        
        

The updated code now invalidates the existing session after a password change and generates a new session for the user. This is done by using the withNewSession method, which discards the existing session data and generates a new session ID.

The withSession method is then used to add the new session data to the response. This ensures that the user is authenticated with the updated credentials in the new session.

The user data is now stored in the request attributes instead of the session data. This is done by using the TypedKey class to define a key for the user data and the attrs method to retrieve the user data from the request attributes. This provides a more secure way to store the user data as it is not exposed in the session data.

The isDefined method is used to check if the user data is present in the request attributes. If the user data is not present, the password change request is rejected with an Unauthorized response.

This code also assumes that you have a mechanism in place to automatically expire sessions after a certain period of inactivity. This is an important part of secure session management as it reduces the risk of session hijacking.

In addition to these changes, you should also implement strong password policies and enforce password complexity requirements to enhance the security of user passwords. Regularly review and update the session management code to address any new vulnerabilities or best practices.

References