Prevention of session hijacking
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.
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.