Skip to main content

Business information leak - Analytics

Need

Protection of sensitive business information from unauthorized access and leakage

Context

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

Description

Non compliant code

import play.api._
import play.api.mvc._

object AnalyticsController extends Controller {
val API_KEY = "YOUR_API_KEY"

def getAnalytics() = Action {
val url = "http://your.analytics.url"
val swaggerUrl = url + "/swagger?apiKey=" + API_KEY
Ok(swaggerUrl)
}
}

The above code represents a vulnerability in a Scala backend application using the Play framework. The AnalyticsController object is responsible for handling requests related to analytics.

The API_KEY is hardcoded and directly embedded in the URL for the Swagger analytics. This is exposed when the getAnalytics function is called, which returns the Swagger URL with the API key as a query parameter.

The problem here is that the API key, which is sensitive business information, can be seen by anyone who can access the URL. This can lead to unauthorized access to the analytics data, revealing business insights that should remain confidential.

Moreover, the API key should not be hardcoded in the source code. If the key is compromised, the only way to change it is to change the source code and redeploy the application, which is not a practical solution for real-world applications.

Steps

  • Remove the API key from the code and store it securely.
  • Implement authentication and authorization mechanisms to restrict access to the analytics endpoint.
  • Use environment variables or configuration files to store sensitive information like the API key.
  • Ensure that the analytics URL is not exposed in the response body or logs.
  • Consider using encryption or obfuscation techniques to protect the analytics URL.
  • Regularly review and update the access control policies for the analytics endpoint.

Compliant code

import play.api._
import play.api.mvc._
import play.api.libs.ws._
import javax.inject.Inject
import scala.concurrent.ExecutionContext

class AnalyticsController @Inject()(ws: WSClient, configuration: Configuration)(implicit ec: ExecutionContext) extends Controller {
def getAnalytics() = Action.async {
val apiKey = configuration.get[String]("apiKey")
val url = configuration.get[String]("analytics.url")
val request = ws.url(url).withHttpHeaders("X-Api-Key" -> apiKey)
request.get().map { response =>
Ok(response.body)
}
}
}

The updated code now securely retrieves the API key and the analytics URL from the application's configuration, rather than hardcoding them into the source code. This is done using Play's Configuration class, which allows for the retrieval of configuration values in a type-safe manner.

The getAnalytics method has been updated to use Play's WSClient to make a GET request to the analytics URL. The API key is included as a header in the request, rather than being appended to the URL. This prevents the API key from being exposed in logs or in the response body.

The getAnalytics method now returns a Future[Result], which allows for asynchronous processing of the request. This is important for performance reasons, as it allows the server to handle other requests while waiting for the response from the analytics service.

The AnalyticsController now requires an instance of WSClient and Configuration to be injected into it. This is done using Play's built-in dependency injection support. This makes the controller easier to test, as these dependencies can be mocked in tests.

Finally, the API key is now stored securely in the application's configuration, rather than being hardcoded into the source code. This makes it easier to rotate the API key if necessary, and prevents the API key from being exposed in the source code.

References