File Upload Functionality Detected
Description
This finding identifies web pages that contain file upload functionality, allowing users to submit files to the server. While file upload is a common and often necessary feature in web applications, it introduces significant security risks if not properly implemented. Attackers can exploit poorly secured upload mechanisms to upload malicious files (such as web shells, executable scripts, or oversized files) that could lead to remote code execution, server compromise, or denial of service attacks.
Remediation
Implement comprehensive file upload security controls using a defense-in-depth approach:
1. File Type Validation:
- Use a whitelist approach to allow only specific, necessary file extensions (e.g., .jpg, .png, .pdf)
- Validate the actual file content and MIME type, not just the extension, using file signature verification (magic numbers)
- Reject files with double extensions (e.g., file.php.jpg) or no filename (e.g., .htaccess, web.config)
2. File Storage Security:
- Store uploaded files outside the web root directory whenever possible
- If files must be web-accessible, store them in a dedicated directory with execute permissions disabled
- Rename uploaded files to randomly generated names to prevent direct access and execution
- Set restrictive file permissions (read-only for web server user)
3. Content Validation:
- Scan uploaded files with antivirus/anti-malware solutions
- Implement file size limits to prevent denial of service
- For images, re-encode them using a trusted image processing library to strip potential embedded malicious code
4. Access Controls:
- Require authentication for file upload functionality
- Implement rate limiting to prevent abuse
- Serve uploaded files with a Content-Disposition: attachment header to force downloads rather than execution
- Use a separate domain or subdomain for serving user-uploaded content
Example (PHP):
// Whitelist allowed extensions
$allowedExtensions = ['jpg', 'jpeg', 'png', 'pdf'];
$fileExtension = strtolower(pathinfo($_FILES['upload']['name'], PATHINFO_EXTENSION));
if (!in_array($fileExtension, $allowedExtensions)) {
die('Invalid file type');
}
// Verify MIME type
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $_FILES['upload']['tmp_name']);
$allowedMimes = ['image/jpeg', 'image/png', 'application/pdf'];
if (!in_array($mimeType, $allowedMimes)) {
die('Invalid file content');
}
// Generate random filename and store outside web root
$newFilename = bin2hex(random_bytes(16)) . '.' . $fileExtension;
$uploadPath = '/var/uploads/' . $newFilename;
move_uploaded_file($_FILES['upload']['tmp_name'], $uploadPath);
chmod($uploadPath, 0644);