Skip to main content

External control of file name or path

Need

Prevention of unauthorized access and manipulation of file paths and names

Context

  • Usage of C# 7.1 for advanced language features and enhancements
  • Usage of Microsoft.AspNetCore.Mvc for building web applications with ASP.NET Core
  • Usage of Microsoft.AspNetCore.Http for handling HTTP requests and responses in ASP.NET Core applications
  • Usage of System.IO for input/output operations in .NET development

Description

Non compliant code

public async Task<IActionResult> UploadFile(IFormFile file)
{
if (file == null || file.Length == 0)
{
return Content("file not selected");
}

var path = Path.Combine(
Directory.GetCurrentDirectory(), "wwwroot",
file.FileName);

using (var stream = new FileStream(path, FileMode.Create))
{
await file.CopyToAsync(stream);
}

return RedirectToAction("Files");
}

This piece of code is an action method in an ASP.NET Core controller that handles file uploads. It takes an IFormFile object as parameter which represents the file being uploaded.

The vulnerability lies in the following line of code:

var path = Path.Combine(
Directory.GetCurrentDirectory(), "wwwroot",
file.FileName);

This line of code determines the location where the uploaded file will be saved. It combines the current directory of the application, the "wwwroot" folder (which is the default folder for static files in ASP.NET Core), and the name of the uploaded file to form the path.

The problem is that it uses the FileName property of the IFormFile object directly without any sanitization or validation. This FileName property is controlled by the user who uploads the file. An attacker can manipulate the file name to include path traversal characters (like "../") to change the directory to which the file will be saved, potentially overwriting critical files or saving the file to a location that gives them unauthorized access. This is known as a path traversal attack.

Steps

  • Validate the file name to ensure it does not contain any malicious characters or path traversal sequences.
  • Generate a unique file name to prevent overwriting existing files.
  • Store the uploaded file in a secure location outside of the web root directory.
  • Use a whitelist approach to specify the allowed file extensions.
  • Implement proper access controls to restrict unauthorized access to the uploaded files.
  • Consider implementing file size restrictions to prevent denial of service attacks.
  • Implement logging and monitoring to detect any suspicious activities related to file uploads.

Compliant code

public async Task<IActionResult> UploadFile(IFormFile file)
{
if (file == null || file.Length == 0)
{
return Content("file not selected");
}

// 1. Validate the file name
var fileName = Path.GetFileName(file.FileName);
if (fileName.Contains(".."))
{
return BadRequest("Invalid file name.");
}

// 2. Generate a unique file name
var uniqueFileName = Guid.NewGuid().ToString() + Path.GetExtension(fileName);

// 3. Store the uploaded file in a secure location
var path = Path.Combine(
Directory.GetCurrentDirectory(), "secure_folder",
uniqueFileName);

// 4. Whitelist file extensions
var allowedExtensions = new[] { ".jpg", ".png", ".pdf" };
if (!allowedExtensions.Contains(Path.GetExtension(uniqueFileName).ToLower()))
{
return BadRequest("Invalid file extension.");
}

using (var stream = new FileStream(path, FileMode.Create))
{
await file.CopyToAsync(stream);
}

// 5. Implement proper access controls in the file system
// 6. Consider implementing file size restrictions in the client side
// 7. Implement logging and monitoring

return RedirectToAction("Files");
}

The updated code includes several security measures to prevent external control of file name or path:

  1. Validate the file name: The code checks if the file name contains "..", which is a path traversal sequence. If it does, the code returns an error message.

  2. Generate a unique file name: The code generates a unique file name using a GUID (Globally Unique Identifier) and the original file extension. This prevents overwriting existing files.

  3. Store the uploaded file in a secure location: The code saves the file in a directory named "secure_folder", which should be located outside of the web root directory.

  4. Whitelist file extensions: The code checks the file extension against a list of allowed extensions. If the file extension is not in the list, the code returns an error message.

  5. Implement proper access controls: This is not shown in the code, but you should set up proper access controls in the file system to restrict unauthorized access to the uploaded files.

  6. Consider implementing file size restrictions: This is also not shown in the code, but you should consider implementing file size restrictions in the client side to prevent denial of service attacks.

  7. Implement logging and monitoring: This is not shown in the code, but you should implement logging and monitoring to detect any suspicious activities related to file uploads.

References