Allowing users to upload files is a common requirement for modern applications. Profile pictures, invoices, PDFs, Excel spreadsheets, images, and other documents are frequently uploaded through ASP.NET Core applications. While file uploads appear straightforward, they also introduce significant security and performance risks if not implemented correctly.
Unrestricted file uploads can lead to malware distribution, remote code execution, denial-of-service attacks, storage exhaustion, and sensitive data exposure. ASP.NET Core provides the building blocks for secure file handling, but developers must combine validation, storage, and security best practices to build a production-ready solution.
Rather than accepting uploaded files blindly, this article explains how to validate, store, and protect uploaded files in ASP.NET Core.
Note: Never trust any information provided by the client, including file names, file extensions, MIME types, or file sizes. Always validate uploads on the server.
Why Secure File Uploads Matter
Improper file upload handling can result in:
Malware uploads
Remote code execution
Storage exhaustion
Large file denial-of-service attacks
Unauthorized file access
Data leakage
Compliance violations
A secure upload pipeline protects both your infrastructure and your users.
Common File Upload Scenarios
Typical upload scenarios include:
Profile images
PDF documents
Excel spreadsheets
Product images
Medical records
User attachments
Video uploads
Invoice documents
Each scenario may require different validation and storage policies.
File Upload Workflow
flowchart LR
A[Client]
B[ASP.NET Core API]
C{Validate File}
D[Virus Scan]
E[(File Storage)]
F[(Database)]
A --> B
B --> C
C -->|Valid| D
C -->|Invalid| A
D -->|Safe| E
E --> F
Every uploaded file should pass through validation before being stored.
Accepting File Uploads
ASP.NET Core uses the IFormFile interface to represent uploaded files.
[HttpPost("upload")]
public async Task<IActionResult> Upload(IFormFile file)
{
if (file == null)
return BadRequest();
return Ok();
}
IFormFile provides access to the uploaded file's name, size, content type, and stream.
Validate File Size
Large uploads can consume excessive server resources.
const long MaxFileSize = 5 * 1024 * 1024;
if (file.Length > MaxFileSize)
{
return BadRequest("File exceeds size limit.");
}
Define upload limits based on business requirements rather than accepting arbitrarily large files.
Validate File Extension
Allow only supported file types.
var allowedExtensions =
new[] { ".pdf", ".jpg", ".jpeg", ".png" };
var extension =
Path.GetExtension(file.FileName)
.ToLowerInvariant();
if (!allowedExtensions.Contains(extension))
{
return BadRequest("Unsupported file type.");
}
Extension validation is only one layer of defense and should not be relied upon by itself.
Validate Content Type
Verify the MIME type supplied with the request.
var allowedTypes = new[]
{
"application/pdf",
"image/jpeg",
"image/png"
};
if (!allowedTypes.Contains(file.ContentType))
{
return BadRequest("Invalid content type.");
}
Content types can be spoofed, so combine this check with additional validation techniques.
Generate Safe File Names
Never store user-provided file names directly.
var fileName =
$"{Guid.NewGuid()}{extension}";
Random file names prevent overwriting existing files and reduce the risk of path traversal attacks.
Save the Uploaded File
Store the file outside the web root whenever possible.
var path = Path.Combine(
uploadsFolder,
fileName);
using var stream =
System.IO.File.Create(path);
await file.CopyToAsync(stream);
Keeping uploaded files outside wwwroot prevents direct public access.
Storage Options
Different applications require different storage strategies.
Join the conversation! Your thoughts help the community grow.