Insecure file upload - Scala

Insecure file upload - Scala

Need

Secure file upload and validation

Context

  • Usage of Scala for building scalable and functional applications
  • Usage of play.api.mvc for handling HTTP requests and responses in Play Framework
  • Usage of play.api.libs.Files for handling file operations in a Play Framework application
  • Usage of java.io.File for file handling in Java

Description

Non compliant code

        import play.api.mvc._
import play.api.libs.Files._
import java.io.File

object FileController extends Controller {
  def upload = Action(parse.temporaryFile) { request =>
    request.body.moveTo(new File("/path/to/uploaded/files/" + request.body.filename))
    Ok("File uploaded")
  }
}
        
        

In the above code, we have a simple Play Framework controller that accepts file uploads. The upload action is handling a multipart/form-data request, where the file is temporarily stored and then moved to a specific directory.

The vulnerability here is that there's no validation or sanitization of the uploaded files. This means:

1. Files with any extension can be uploaded, including potentially harmful ones like .html, .php, .exe, etc. These can be used for code injection, remote code execution, or other malicious activities.

2. Files with double extensions can be uploaded. For example, an attacker could upload a file named safe.txt.exe. The system might only check the last extension and consider it safe, while the operating system executes it as an executable file.

3. There's no validation of the file content. An attacker could upload a file containing malicious code, which could be executed if the file is interpreted by a server-side script interpreter (e.g., if the file is .php and the server is configured to run PHP scripts).

This is a serious security vulnerability, as it could allow an attacker to execute arbitrary code on the server, potentially leading to full system compromise.

Steps

  • Implement file type validation to ensure that only allowed file types can be uploaded.
  • Use a secure file storage location and ensure that the uploaded files cannot be executed as code.
  • Implement file content validation to check for malicious code or potential security threats.
  • Set appropriate file permissions to restrict access to the uploaded files.
  • Implement file size restrictions to prevent the upload of excessively large files.
  • Consider implementing additional security measures such as virus scanning or file integrity checks.

Compliant code

        import play.api.mvc._
import play.api.libs.Files._
import java.io.File
import java.nio.file.{Files, Paths}

object FileController extends Controller {
  val allowedExtensions = List(".jpg", ".png", ".gif")

  def upload = Action(parse.temporaryFile) { request =>
    val filename = request.body.filename
    val extension = filename.substring(filename.lastIndexOf("."))

    if (!allowedExtensions.contains(extension)) {
      BadRequest("Invalid file extension")
    } else if (Files.probeContentType(Paths.get(filename)) == "application/x-msdownload") {
      BadRequest("Executable files are not allowed")
    } else {
      request.body.moveTo(new File("/secure/path/to/uploaded/files/" + filename), replace = true)
      Ok("File uploaded")
    }
  }
}
        
        

The updated code includes a list of allowed file extensions. When a file is uploaded, the code checks the file's extension against this list. If the file's extension is not in the list, the server responds with a "Bad Request" error.

The code also checks the file's MIME type using the Files.probeContentType method. If the MIME type is application/x-msdownload, which is commonly associated with executable files, the server responds with a "Bad Request" error.

Finally, the code moves the uploaded file to a secure location. The replace = true option ensures that if a file with the same name already exists in the destination directory, the existing file will be replaced with the uploaded file. This prevents an attacker from uploading a file with the same name as an existing file in an attempt to overwrite the existing file.

This solution addresses the insecure file upload vulnerability by ensuring that only files with allowed extensions can be uploaded, and by preventing the upload of executable files. It also secures the storage of uploaded files by using a secure file storage location and by replacing existing files with the same name.

References