Insecure file upload - Files Limit
Need
To prevent system resources exhaustion by limiting the number of files uploaded and replacing old files with new ones.
Context
- Usage of Elixir (1.12.0 and above) for building scalable and fault-tolerant applications
- Usage of Phoenix Framework for building web applications
- Usage of Plug.Upload for handling file uploads in Elixir
Description
Non compliant code
defmodule MyAppWeb.UploadController do
use MyAppWeb, :controller
def upload(conn, %{"file" => file}) do
{:ok, _} = File.write("./uploads/" <> file.filename, file.read)
send_resp(conn, 200, "File uploaded")
end
end
In this insecure code example, a new file is written to the server's storage every time the upload endpoint is hit. There is no limit to the number of files that can be uploaded, and old files are not replaced with new ones. This could potentially lead to resource exhaustion on the server.
Steps
- Modify the upload function to delete old files before writing new ones.
- Apply request throttling to limit the rate at which files can be uploaded.
Compliant code
defmodule MyAppWeb.UploadController do
use MyAppWeb, :controller
def upload(conn, %{"file" => file}) do
dir = "./uploads/"
old_files = File.ls!(dir)
Enum.each(old_files, &File.rm(dir <> &1))
{:ok, _} = File.write(dir <> file.filename, file.read)
send_resp(conn, 200, "File uploaded")
end
defp limit_rate(conn, _opts) do
:timer.sleep(1000)
conn
end
plug :limit_rate when action in [:upload]
end
In this secure code example, the server deletes old files before writing new ones. Additionally, a plug function limits the rate at which files can be uploaded, thus preventing resource exhaustion on the server.