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
Insecure Code Example
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.
Secure Code Example
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
Last updated
2023/09/18