Directory listing - Scala

Directory listing - Scala

Need

Prevention of unauthorized directory listing

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.Files for file handling in Play Framework

Description

Non compliant code

        import play.api.mvc._
import play.api.libs.Files

class HomeController @Inject()(cc: ControllerComponents) extends AbstractController(cc) {
  def index = Action {
    Ok.sendFile(Files.get("/public/"))
  }
}
        
        

The code above is a Scala Play Framework controller that serves the files in the "/public/" directory when the index route is hit. The Ok.sendFile method sends the file (in this case, a directory) as a response.

This code is vulnerable because it exposes the directory listing of the "/public/" directory to the client. An attacker can potentially see all the files and subdirectories in the "/public/" directory. This can provide valuable information to an attacker, such as the structure of the files on the server, the types of files stored, etc.

The vulnerability lies in the Ok.sendFile(Files.get("/public/")) line, where the server is instructed to send the entire directory as a response without any checks or restrictions.

This vulnerability is known as "Directory Listing" vulnerability. It is a type of information disclosure vulnerability where an attacker can gain information about the application that can be used for further attacks.

Steps

  • Disable directory listing in the web server configuration.
  • Remove the code that sends the directory listing response.
  • Implement proper access control to restrict access to sensitive directories.
  • Use a file server or a web server to serve static files instead of directly accessing the file system.
  • Implement input validation and sanitization to prevent path traversal attacks.

Compliant code

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

class HomeController @Inject()(cc: ControllerComponents) extends AbstractController(cc) {
  def index(fileName: String) = Action {
    val file = new File("/public/" + fileName)
    if (file.exists() && !file.isDirectory) {
      Ok.sendFile(file)
    } else {
      NotFound("File not found")
    }
  }
}
        
        

The updated code now takes a fileName parameter in the index function. This parameter is used to construct the path to the file that should be sent in response to the client's request.

The if condition checks if the file exists and if it is not a directory. If both conditions are true, the file is sent as a response. If either condition is false, a "File not found" message is sent as a response.

This way, we prevent directory listing as the server will only send a file if it exists and is not a directory.

Please note that this is a basic solution and does not include input validation and sanitization to prevent path traversal attacks. For a production-grade solution, you should also implement proper access control to restrict access to sensitive directories and use a file server or a web server to serve static files instead of directly accessing the file system.

References