Skip to main content

Insecurely generated token - Lifespan

Need

Securely generate session tokens with appropriate lifespan

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 java.util.Date for handling date and time in Java applications

Description

Non compliant code

import play.api.mvc._
import java.util.Date

class SessionController extends Controller {

def createSession = Action { request =>
val token = java.util.UUID.randomUUID().toString
val expiryDate = new Date(System.currentTimeMillis() + 5 * 24 * 60 * 60 * 1000)
Ok("Session Created").withSession("token" -> token, "expiryDate" -> expiryDate.toString)
}
}

In the above code, the createSession method in SessionController class is responsible for creating a new session. It generates a random session token using java.util.UUID.randomUUID().toString and sets an expiry date for the token as current time plus 5 days (52460601000 milliseconds).

The session is then created with these token and expiry date using Ok("Session Created").withSession("token" -> token, "expiryDate" -> expiryDate.toString).

The vulnerability here is that the session token has a long lifespan of approximately 5 days. If an attacker is able to get hold of the session token, they can use it to impersonate the user for up to 5 days. This could lead to unauthorized access and potential data breaches.

A more secure approach would be to reduce the lifespan of the session token and implement mechanisms to invalidate the token after a certain period of inactivity.

Steps

  • Generate session tokens with a shorter expiration time.
  • Use a secure random number generator to generate session tokens.
  • Store the expiration time of the session token securely.
  • Implement a mechanism to check the expiration time of session tokens and invalidate expired tokens.

Compliant code

import play.api.mvc._
import java.util.UUID
import java.security.SecureRandom
import java.time.Instant
import java.time.temporal.ChronoUnit

class SessionController extends Controller {

private val secureRandom = new SecureRandom()

def createSession = Action { request =>
val token = new UUID(secureRandom.nextLong(), secureRandom.nextLong()).toString
val expiryDate = Instant.now().plus(30, ChronoUnit.MINUTES)
Ok("Session Created").withSession("token" -> token, "expiryDate" -> expiryDate.toString)
}

def checkSession = Action { request =>
request.session.get("expiryDate") match {
case Some(date) =>
if (Instant.parse(date).isBefore(Instant.now())) {
Unauthorized("Session Expired")
} else {
Ok("Session Valid")
}
case None => Unauthorized("No Session")
}
}
}

The updated code now uses a SecureRandom instance to generate session tokens, which are more secure than the previously used UUID.randomUUID(). The SecureRandom class provides a cryptographically strong random number generator.

The expiration time of the session tokens has been reduced from 5 days to 30 minutes. This is done by using Instant.now().plus(30, ChronoUnit.MINUTES). This reduces the window of opportunity for an attacker to use a stolen session token.

A new method checkSession has been added. This method checks if the session token has expired by comparing the stored expiry date with the current time. If the session token has expired, it returns an "Unauthorized" response. If the session token is valid, it returns an "Ok" response. If no session token is found, it also returns an "Unauthorized" response. This ensures that expired session tokens are invalidated and cannot be used.

References