Skip to main content

Business information leak - Users

Need

Protection of sensitive business information and user data

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 play.api.mvc.AbstractController for building controllers in Play Framework
  • Usage of play.api.mvc.ControllerComponents for handling HTTP requests and responses in Play Framework
  • Usage of play.api.mvc.Action for handling HTTP requests in Play Framework
  • Usage of play.api.mvc.Request for handling HTTP requests in Play Framework
  • Usage of play.api.mvc.AnyContent for handling any type of content in Play Framework

Description

Non compliant code

import play.api.mvc._

class UserController @Inject()(cc: ControllerComponents) extends AbstractController(cc) {

def listUsers = Action { implicit request: Request[AnyContent] =>
// Assume UserRepo is a repository that provides access to user data
val users = UserRepo.getAllUsers()
Ok(users)
}
}

This code snippet shows a Play Framework controller that provides an endpoint to list all users in the system. The listUsers action fetches all users from a hypothetical UserRepo and returns them in the response.

The vulnerability lies in the fact that this endpoint doesn't have any access control mechanism in place - any user (or even an unauthenticated individual) can send a request to this endpoint and receive a list of all users in the system. This can lead to a business information leak, as it exposes a list of valid users.

The information leak can be exploited in several ways:

  1. An attacker can use the list of users to attempt brute force attacks, trying to guess the passwords of the users.
  2. If the user objects contain sensitive information (like email addresses, phone numbers, etc.), this information can be harvested for phishing attacks or spam.
  3. The list of users can provide valuable information about the organization (like its size, or the names of its employees), which can be used for social engineering attacks.

To fix this vulnerability, the listUsers endpoint should be protected with an appropriate access control mechanism, ensuring that only authorized users can view the list of users.

Steps

  • Avoid returning sensitive business information directly in the response.
  • Implement proper access control mechanisms to restrict unauthorized access to user information.
  • Use authentication and authorization techniques to ensure that only authenticated and authorized users can access the user information.
  • Consider implementing role-based access control (RBAC) to define different levels of access for different user roles.
  • Apply data anonymization or pseudonymization techniques to protect the privacy of user information.
  • Regularly review and update the access control policies and permissions to ensure they are up to date and aligned with the business requirements.
  • Implement logging and monitoring mechanisms to detect and investigate any unauthorized access attempts or suspicious activities related to user information.

Compliant code

import play.api.mvc._
import javax.inject.Inject
import play.api.libs.json.Json

class UserController @Inject()(cc: ControllerComponents, authService: AuthService) extends AbstractController(cc) {

def listUsers = Action { implicit request: Request[AnyContent] =>
// Check if the user is authenticated and authorized
authService.authenticateAndAuthorize(request, "admin") match {
case Some(user) =>
// Assume UserRepo is a repository that provides access to user data
val users = UserRepo.getAllUsers()
// Anonymize the user data before sending it
val anonymizedUsers = users.map(user => user.copy(email = "hidden", password = "hidden"))
Ok(Json.toJson(anonymizedUsers))
case None =>
Unauthorized("You are not authorized to access this resource.")
}
}
}

The updated code includes an AuthService that is used to authenticate and authorize the user making the request. The authenticateAndAuthorize method takes the request and a role as parameters. If the user is authenticated and has the required role, the method returns the user. Otherwise, it returns None.

In the listUsers action, we first check if the user is authenticated and authorized. If they are, we get the list of all users from the UserRepo. Before sending this list in the response, we anonymize the user data by hiding the email and password. This is done using the copy method of the User case class, which creates a new User instance with the specified changes. The anonymized list of users is then converted to JSON and sent in the response.

If the user is not authenticated or authorized, we return a Unauthorized response with a message indicating that they are not authorized to access the resource.

This approach ensures that only authenticated and authorized users can access the user information, and that the information is anonymized before being sent. It also provides a clear response in case of unauthorized access attempts.

References