logo

Database

Server-side request forgery (SSRF)

Need

Prevention of unauthorized server-side requests to arbitrary domains

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

• Usage of play.api.libs.ws for making HTTP requests in a Play Framework application

• Usage of global execution context for concurrent programming in Scala

Description

1. Non compliant code

import play.api.mvc._
import play.api.libs.ws._
import scala.concurrent.ExecutionContext.Implicits.global

class HomeController @Inject()(ws: WSClient) extends Controller {
  def index(url: String) = Action.async { implicit request =>
    ws.url(url).get().map { response =>
    }...

The `HomeController` class has an `index` method that takes a URL as a parameter. This URL is supplied by the user and the server sends a GET request to this URL using the `ws.url(url).get()` method. The server then returns the response from the requested URL to the user. This is an example of Server-side Request Forgery (SSRF) because the server is making a request to an arbitrary URL supplied by the user. The user can exploit this by making the server interact with internal resources that are not normally accessible. For example, a user could input a URL that points to an internal service that is only accessible from the server's network, potentially exposing sensitive information or functionality.

2. Steps

• Validate the 'url' parameter to ensure it is a trusted and valid URL.

• Implement a whitelist of allowed domains that the application can make requests to.

• Sanitize user input to prevent any malicious input from being used in the URL.

• Implement proper error handling and logging to detect and respond to any SSRF attempts.

• Consider using a library or framework that provides built-in protection against SSRF, such as the Play WS library's built-in protection against SSRF.

3. Secure code example

import play.api.mvc._
import play.api.libs.ws._
import scala.concurrent.ExecutionContext.Implicits.global

class HomeController @Inject()(ws: WSClient) extends Controller {
  private val allowedDomains = List("www.trusteddomain1.com", "www.trusteddomain2.com")

    val domain = new java.net.URL(url).getHost...

The updated code includes a whitelist of allowed domains that the application can make requests to. This is done by creating a list of trusted domains (`allowedDomains`). When a request is made, the domain of the provided URL is extracted using `new java.net.URL(url).getHost`. This domain is then checked against the `allowedDomains` list. If the domain is in the list, the request is made as before. If the domain is not in the list, a `BadRequest` response is returned, indicating that the provided domain is not allowed. This approach prevents Server-Side Request Forgery (SSRF) by ensuring that the application can only make requests to trusted domains. It also provides a clear error message when an attempt is made to request a resource from an untrusted domain, which can be useful for logging and detecting malicious activity. Remember to always keep the `allowedDomains` list updated with the domains that you trust and want your application to interact with.