Skip to main content

Automatic information enumeration - Personal Information

Need

Protection of user privacy and prevention of unauthorized access to personal information

Context

  • Usage of Scala 2.11 for building scalable and high-performance applications
  • Usage of play.api.mvc for handling HTTP requests and responses in Play Framework
  • Usage of play.api.libs.json for JSON parsing and manipulation in Play Framework

Description

Non compliant code

import play.api.mvc._

object UserController extends Controller {

def getUser(id: String) = Action {
val user = User.find(id)
Ok(Json.toJson(user))
}
}

In the above code snippet, the getUser function is vulnerable to automatic information enumeration. This function takes a user id as a parameter and returns the corresponding user's information in JSON format.

However, this function doesn't validate or check if the request has a valid token associated with the account, which is a serious security issue. In other words, anyone can send a GET request to this endpoint with any id and retrieve that user's information without having to provide any form of authentication or authorization.

This exposes all users' information, making it possible for an attacker to enumerate through all possible id values and gather personal information about every user in the system. This can lead to serious privacy breaches and potential identity theft.

To fix this vulnerability, it's necessary to implement an authentication mechanism that checks if the request is coming from a legitimate user with a valid token. Only after validating the token should the function return the requested user's information.

Steps

  • Implement authentication and authorization mechanisms to ensure that only authorized users can access user information.
  • Use a token-based authentication system to authenticate users and ensure that the token is required to access user information.
  • Validate the user's identity and permissions before retrieving and returning user information.
  • Implement access control checks to prevent unauthorized access to user information.
  • Ensure that the user ID parameter is properly validated and sanitized to prevent any potential injection attacks.

Compliant code

import play.api.mvc._
import play.api.libs.json._
import scala.concurrent.Future
import play.api.libs.concurrent.Execution.Implicits.defaultContext

case class AuthenticatedRequest[A](user: User, request: Request[A]) extends WrappedRequest[A](request)

object AuthenticatedAction extends ActionBuilder[AuthenticatedRequest] {
def invokeBlock[A](request: Request[A], block: (AuthenticatedRequest[A]) => Future[Result]) =
request.headers.get("X-Auth-Token").flatMap { token =>
User.findByToken(token)
} match {
case Some(user) => block(AuthenticatedRequest(user, request))
case None => Future.successful(Results.Unauthorized)
}
}

object UserController extends Controller {

def getUser(id: String) = AuthenticatedAction.async { implicit request =>
if(request.user.id == id) {
val user = User.find(id)
Future.successful(Ok(Json.toJson(user)))
} else {
Future.successful(Results.Forbidden)
}
}
}

The updated code now includes an AuthenticatedAction object that extends ActionBuilder. This object is used to create a new action that requires authentication. The invokeBlock method is overridden to include a check for the "X-Auth-Token" in the request headers. If the token is found, it is used to find the associated user. If the user is found, the block of code is executed with the authenticated request. If the token or user is not found, an Unauthorized result is returned.

In the getUser method, the AuthenticatedAction is now used instead of the generic Action. This ensures that the user must be authenticated before the user information can be retrieved. Additionally, a check is added to ensure that the authenticated user's ID matches the ID of the user whose information is being requested. If the IDs do not match, a Forbidden result is returned. This prevents users from accessing information of other users.

This code fixes the vulnerability by implementing token-based authentication and authorization checks. It ensures that only the authenticated user can access their own information, preventing automatic information enumeration.

References