Lack of data validation - Trust boundary violation - Scala

Lack of data validation - Trust boundary violation - Scala

Need

Enforce strict data validation and trust boundaries

Context

  • Usage of Scala for building scalable and high-performance applications
  • Usage of play.api.mvc for handling HTTP requests 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._
import play.api.libs.json._

class ApplicationController(cc: ControllerComponents) extends AbstractController(cc) {

  def saveData = Action(parse.json) { request =>
    val value = (request.body \\ "data").as[String]
    val trustedData = "This is trusted data"
    val mixedData = trustedData + value
    Ok("Data received: " + mixedData)
  }
}
        
        

In the above Scala code, we have a Play Framework controller ApplicationController with a method saveData that accepts JSON data from the HTTP request.

The vulnerability lies in the saveData method. This method extracts data from the JSON request body without validating it and mixes it with trusted data. Here, (request.body \\ "data").as[String] extracts the "data" field from the JSON request body and treats it as a string. This extracted data is considered untrusted as it comes from the client and can potentially contain malicious input.

The trusted data is defined as val trustedData = "This is trusted data". The untrusted data (extracted from the request) and the trusted data are then mixed together in val mixedData = trustedData + value.

The problem with this code is that it doesn't validate or sanitize the untrusted data before mixing it with the trusted data. This could lead to a variety of security vulnerabilities such as Cross-Site Scripting (XSS), SQL Injection, or Command Injection depending on how the mixed data is used later in the application. In this case, the mixed data is directly sent back to the client which could lead to Reflected XSS if the untrusted data contains a malicious script.

Steps

  • Separate trusted and untrusted data in different data structures or structured messages.
  • Perform data validation on untrusted data to ensure it meets the expected format and constraints.
  • Use appropriate data validation techniques such as input validation, data sanitization, and data type validation.
  • Implement input validation checks to prevent malicious data from being processed.
  • Apply proper encoding or escaping techniques when combining trusted and untrusted data to prevent injection attacks.
  • Follow secure coding practices and guidelines to ensure data integrity and trust boundaries are maintained.

Compliant code

        import play.api.mvc._
import play.api.libs.json._

class ApplicationController(cc: ControllerComponents) extends AbstractController(cc) {

  def saveData = Action(parse.json) { request =>
    val value = (request.body \\ "data").asOpt[String]
    val trustedData = "This is trusted data"
    value match {
      case Some(untrustedData) if validateData(untrustedData) =>
        val sanitizedData = sanitizeData(untrustedData)
        val mixedData = trustedData + sanitizedData
        Ok("Data received: " + mixedData)
      case _ => BadRequest("Invalid data")
    }
  }

  def validateData(data: String): Boolean = {
    // Implement your validation logic here
    true
  }

  def sanitizeData(data: String): String = {
    // Implement your sanitization logic here
    data
  }
}
        
        

The updated code separates trusted and untrusted data into different variables. The untrusted data is extracted from the request body and is validated and sanitized before it is used.

The validateData function is used to check if the untrusted data meets the expected format and constraints. If the data is invalid, a BadRequest response is returned. This function should be implemented with the specific validation logic for the application.

The sanitizeData function is used to clean the untrusted data to ensure it does not contain any malicious content. This function should be implemented with the specific sanitization logic for the application.

The trusted and sanitized untrusted data are then combined and returned in the response. This ensures that the data integrity and trust boundaries are maintained.

References