Skip to main content

Insecure file upload - Files Limit

Need

Enforce file upload limits to prevent resource exhaustion and potential security risks

Context

  • Usage of C# for developing robust and efficient software applications
  • Usage of Microsoft.AspNetCore.Http for handling HTTP requests and responses in ASP.NET Core applications
  • Usage of System.IO for Input and Output operations in .NET development
  • Usage of System.Threading.Tasks for asynchronous programming in .NET

Description

Non compliant code

using Microsoft.AspNetCore.Http;
using System.IO;
using System.Threading.Tasks;

public class UploadController : Controller
{
[HttpPost("UploadFiles")]
public async Task<IActionResult> Post(List<IFormFile> files)
{
long size = files.Sum(f => f.Length);

foreach (var formFile in files)
{
if (formFile.Length > 0)
{
var filePath = Path.GetTempFileName();

using (var stream = System.IO.File.Create(filePath))
{
await formFile.CopyToAsync(stream);
}
}
}

return Ok(new { count = files.Count, size });
}
}

The above code represents an endpoint in an ASP.NET Core application that allows for the uploading of files. The UploadFiles method is decorated with the HttpPost attribute, indicating that it responds to HTTP POST requests. This method accepts a list of files as input, which are instances of IFormFile.

The number of files that can be uploaded is not limited in any way. This is a security vulnerability, as an attacker could potentially upload an unlimited number of files, potentially causing a denial of service by filling up the server's storage or causing other performance issues.

Moreover, the uploaded files are stored in the server's temporary files directory and are not deleted after they have been processed. This could lead to a situation where the server's storage is filled up with old, unnecessary files.

The size variable is used to calculate the total size of all uploaded files, but it does not limit the total size or number of uploaded files.

The method returns an HTTP 200 OK response, along with a JSON object that includes the number of files and total size of the uploaded files.

Steps

  • Implement a limit on the number of files that can be uploaded per unit of time.
  • Delete the previous files from the server before uploading a new one.
  • Validate the file size before saving it to the server.
  • Use a secure file storage location instead of the temporary folder.

Compliant code

using Microsoft.AspNetCore.Http;
using System.IO;
using System.Threading.Tasks;
using System.Linq;
using System.Collections.Generic;

public class UploadController : Controller
{
private const int MaxFilesPerHour = 100; // Set your limit
private static Dictionary<string, DateTime> FileUploads = new Dictionary<string, DateTime>();

[HttpPost("UploadFiles")]
public async Task<IActionResult> Post(List<IFormFile> files)
{
// Check if the number of files uploaded in the last hour exceeds the limit
var uploadsLastHour = FileUploads.Where(x => x.Value > DateTime.Now.AddHours(-1)).Count();
if (uploadsLastHour + files.Count > MaxFilesPerHour)
{
return BadRequest("Upload limit exceeded");
}

long size = files.Sum(f => f.Length);

foreach (var formFile in files)
{
if (formFile.Length > 0)
{
// Delete previous file
var filePath = Path.GetTempFileName();
if (System.IO.File.Exists(filePath))
{
System.IO.File.Delete(filePath);
}

// Save new file
using (var stream = System.IO.File.Create(filePath))
{
await formFile.CopyToAsync(stream);
}

// Add to the list of recent uploads
FileUploads.Add(filePath, DateTime.Now);
}
}

// Remove entries older than 1 hour
var entriesToRemove = FileUploads.Where(x => x.Value <= DateTime.Now.AddHours(-1)).ToList();
foreach (var entry in entriesToRemove)
{
FileUploads.Remove(entry.Key);
}

return Ok(new { count = files.Count, size });
}
}

The code above is a modification of the original file upload controller. It introduces a limit on the number of files that can be uploaded per hour, and it deletes the previous file before uploading a new one.

The MaxFilesPerHour constant sets the limit on the number of files that can be uploaded per hour. The FileUploads dictionary keeps track of the files that have been uploaded and the time they were uploaded.

In the Post method, we first check if the number of files uploaded in the last hour plus the number of files being uploaded now exceeds the limit. If it does, we return a "Bad Request" response.

Then, for each file in the request, we delete the previous file (if it exists) before saving the new file. We also add the file to the FileUploads dictionary with the current time.

Finally, we remove entries from the FileUploads dictionary that are older than 1 hour.

This code ensures that the number of files uploaded per hour does not exceed a certain limit, and it prevents old files from remaining on the server when new ones are uploaded.

References