Secure file handling and storage
import play.api.mvc._
def upload = Action(parse.multipartFormData) { request =>
request.body.file("picture").map { picture =>
import java.io.File
val filename = picture.filename
val contentType = picture.contentType
picture.ref.moveTo(new File(s"/user/uploads/$filename"))
Ok("File uploaded")
}.getOrElse {
Redirect(routes.Application.index).flashing(
"error" -> "Missing file"
)
}
}
The above Scala function
upload
is handling file uploads in a Play framework application. It is using
multipartFormData
to parse the incoming request.
The vulnerability lies in this line of code:
picture.ref.moveTo(new File(s"/user/uploads/$filename"))
../../etc/passwd
, which could overwrite important system files if the application has the necessary permissions, leading to serious security implications. /user/uploads/
directory, an attacker could potentially access this information by guessing the filenames.
import play.api.mvc._
import java.nio.file.{Paths, Files}
import java.util.UUID
def upload = Action(parse.multipartFormData) { request =>
request.body.file("picture").map { picture =>
val filename = picture.filename
val contentType = picture.contentType
val sanitizedFileName = filename.replaceAll("[^a-zA-Z0-9\\\\.\\\\-]", "_")
val uniqueFileName = UUID.randomUUID().toString + "_" + sanitizedFileName
val secureDirectory = "/secure/uploads/"
val filePath = Paths.get(secureDirectory, uniqueFileName)
if (!Files.exists(filePath)) {
picture.ref.moveTo(filePath.toFile)
Ok("File uploaded")
} else {
InternalServerError("Error in file upload")
}
}.getOrElse {
Redirect(routes.Application.index).flashing(
"error" -> "Missing file"
)
}
}
The updated code includes several measures to mitigate the risk of external control of file name or path vulnerability.
1. File Name Sanitization: The file name is sanitized by replacing any character that is not alphanumeric, a period, or a hyphen with an underscore. This prevents any potentially malicious characters or sequences from being included in the file name.
2. Unique File Name Generation: A unique file name is generated by appending a UUID to the sanitized file name. This prevents overwriting of existing files.
3. Secure Directory: The uploaded files are saved in a secure directory (
/secure/uploads/
). This directory should be outside of the web root to prevent direct access to the uploaded files.
4. File Existence Check: Before moving the file, the code checks if a file with the same name already exists in the directory. If it does, an error is returned.
5. Error Handling: If the file is missing, the user is redirected to the index page with an error message.
Remember to set proper access controls on the
/secure/uploads/
directory to restrict unauthorized access. Consider using a file storage service or database for storing files if your application handles a large number of file uploads or requires more advanced features.