logo

Insecure or unset HTTP headers - Accept - Scala


Need

Enforcement of secure and specific Accept headers


Context

  1. Usage of Scala for building scalable and functional applications
  2. Usage of play.api.mvc for handling HTTP requests and responses in Play Framework

Description

Insecure Code Example

import play.api.mvc._

object ApplicationController extends Controller {
  def index = Action { implicit request =>
    Ok("Hello World!")
  }
}

In the above Scala code, a basic server is set up using the Play Framework. The server has an endpoint at the root ("/") which responds to HTTP requests. The issue here is that the server does not set the `Accept` header for the requests it processes. The `Accept` header is important as it tells the server what media types are acceptable for the client. This is important as it allows the server to send a response in a format that the client can understand and process. In the current state of the code, the server does not specify an `Accept` header, which means that it will accept any media type. This can lead to a vulnerability where an attacker may send a request with a media type that causes unexpected behavior when the server tries to process it. This could potentially lead to a range of issues, from server errors to security vulnerabilities.

Steps

  1. Implement input validation to ensure that the Accept header is set and contains a valid MIME type.
  2. Restrict the allowed MIME types in the Accept header to only those that are expected by the application.
  3. Handle invalid or unexpected MIME types in a secure manner, such as returning an appropriate error response or rejecting the request.
  4. Consider implementing content negotiation to allow the application to respond with the most appropriate representation based on the client's Accept header.

Secure Code Example

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

object ApplicationController extends Controller {
  def index = Action(parse.tolerantText) { implicit request =>
    request.headers.get("Accept") match {
      case Some(mime) if mime == "application/json" || mime == "text/html" =>
        Ok("Hello World!")
      case _ =>
        BadRequest("Invalid or missing Accept header")
    }
  }
}

The updated code now includes a check for the `Accept` header in the HTTP request. This is done using the `request.headers.get("Accept")` method, which retrieves the value of the `Accept` header if it exists. The `match` statement is used to handle different cases based on the value of the `Accept` header. If the `Accept` header is set and its value is either `application/json` or `text/html`, the request is processed and the response "Hello World!" is returned. These are the MIME types that the application expects and can handle. If the `Accept` header is missing or its value is not one of the expected MIME types, the request is rejected and a `BadRequest` response is returned with the message "Invalid or missing Accept header". This ensures that the application behaves securely when it encounters an invalid or unexpected MIME type. The `parse.tolerantText` method is used to parse the request body as text, allowing for a more flexible handling of different content types. This is an example of content negotiation, where the application can respond with the most appropriate representation based on the client's `Accept` header. This approach helps to mitigate the risk of an attacker causing unexpected behaviors by sending requests with incorrect content types. It ensures that the application only processes requests with expected and valid MIME types, thereby enhancing its security.


References

  • 153 - Insecure or unset HTTP headers - Accept

  • Last updated

    2023/09/18