Skip to main content

Insecurely generated cookies

Need

Secure generation and management of cookies

Context

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

Description

Non compliant code

import play.api.mvc._

object Application extends Controller {

def index = Action {
val cookie = Cookie("sessionId", "user123")
Ok("Welcome!").withCookies(cookie)
}
}

In the above code, we are creating a new cookie with the name sessionId and value user123. This cookie is then added to the HTTP response using the withCookies method.

The vulnerability here is that the cookie is not marked as Secure or HttpOnly.

  • The Secure attribute tells the browser to only send the cookie if the request is being sent over a secure channel such as HTTPS. This will help prevent the cookie from being passed over unencrypted requests. If the Secure attribute is not set, then the cookie will be transmitted in clear text if the user visits any HTTP URLs within the cookie's scope. This could make it vulnerable to interception and eavesdropping.

  • The HttpOnly attribute is used to help prevent attacks such as cross-site scripting, because it does not allow the cookie to be accessed via a client-side script such as JavaScript. This means that even if a cross-site scripting (XSS) attack is successful, the attacker would not be able to access the cookie.

Not setting these attributes can lead to potential security risks such as disclosure of sensitive information and session hijacking.

Steps

  • Use the secure flag when setting cookies to ensure they are only sent over HTTPS.
  • Set the HttpOnly flag when setting cookies to prevent client-side scripts from accessing them.
  • Set the SameSite attribute to 'Strict' or 'Lax' to prevent cross-site request forgery (CSRF) attacks.
  • Generate a random and unique session ID for the cookie value instead of using a static value.
  • Consider using a secure session management library provided by the framework or a trusted third-party library.

Compliant code

import play.api.mvc._
import play.api.libs.crypto.DefaultCookieSigner

object Application extends Controller {

def index = Action {
val sessionId = java.util.UUID.randomUUID().toString // Generate a random session ID
val cookieSigner = new DefaultCookieSigner
val signedSessionId = cookieSigner.sign(sessionId) // Sign the session ID
val cookie = Cookie("sessionId", signedSessionId, httpOnly = true, secure = true, sameSite = Some(Cookie.SameSite.Strict))
Ok("Welcome!").withCookies(cookie)
}
}

The updated code now sets the secure flag to true when creating the cookie. This ensures that the cookie is only sent over HTTPS, preventing it from being sent in plain text.

The httpOnly flag is also set to true, which prevents client-side scripts from accessing the cookie. This is a crucial security measure to prevent cross-site scripting (XSS) attacks.

The SameSite attribute is set to Strict, which means the cookie will only be sent in a first-party context (i.e., if the URL displayed in the address bar is the same as the cookie’s domain). This helps to mitigate cross-site request forgery (CSRF) attacks.

Instead of using a static value ("user123") for the session ID, the code now generates a random and unique session ID using java.util.UUID.randomUUID().toString. This makes it much harder for an attacker to guess the session ID and hijack the session.

Finally, the session ID is signed using Play's DefaultCookieSigner. This ensures that the session ID cannot be tampered with, as any changes to the session ID will invalidate the signature.

References