mirror of
https://github.com/itflow-org/itflow
synced 2026-08-17 13:05:12 +00:00
Harden checkFileUpload: drop content hashing for random storage names
Replace md5(file_contents)+randomString(2) naming with randomString(32). No longer reads the file into memory (removes file_get_contents), so validation is O(1) regardless of size or upload count. Add is_uploaded_file() and UPLOAD_ERR_OK checks, use pathinfo() for extension extraction, and return false consistently on all failures (oversize previously returned a truthy error string that callers treated as a valid filename).
This commit is contained in:
@@ -106,43 +106,41 @@ function sanitizeFilename($filename, $strict = false) {
|
|||||||
return $filename;
|
return $filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass $_FILE['file'] to check an uploaded file before saving it
|
// Validate a single $_FILES[...] entry before saving it.
|
||||||
function checkFileUpload($file, $allowed_extensions)
|
// Returns a safe, unguessable storage filename (random + original extension)
|
||||||
{
|
// on success, or false on ANY failure. The client's own filename is never used
|
||||||
// Variables
|
// on disk, so path tricks and double extensions (evil.php.jpg) are irrelevant.
|
||||||
$name = $file['name'];
|
function checkFileUpload($file, $allowed_extensions) {
|
||||||
$tmp = $file['tmp_name'];
|
// Must be a well-formed single-file upload (reject arrays / malformed entries)
|
||||||
$size = $file['size'];
|
if (!isset($file['tmp_name'], $file['error'], $file['size'], $file['name'])
|
||||||
|
|| is_array($file['tmp_name'])) {
|
||||||
$extarr = explode('.', $name);
|
|
||||||
$extension = strtolower(end($extarr));
|
|
||||||
|
|
||||||
// Check a file is actually attached/uploaded
|
|
||||||
if ($tmp === '') {
|
|
||||||
// No file uploaded
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the extension is allowed
|
// Must be a successful upload
|
||||||
if (!in_array($extension, $allowed_extensions)) {
|
if ($file['error'] !== UPLOAD_ERR_OK) {
|
||||||
// Extension not allowed
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the size is under 500 MB
|
// Must be a genuine HTTP upload, not an arbitrary server path
|
||||||
$maxSizeBytes = 500 * 1024 * 1024; // 500 MB
|
if (!is_uploaded_file($file['tmp_name'])) {
|
||||||
if ($size > $maxSizeBytes) {
|
return false;
|
||||||
return "File size exceeds the limit.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the file content
|
// Reject empty files and enforce the 500 MB ceiling
|
||||||
$fileContent = file_get_contents($tmp);
|
$size = (int) $file['size'];
|
||||||
|
if ($size <= 0 || $size > 500 * 1024 * 1024) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Hash the file content using SHA-256
|
// Allow-list check against the FINAL extension only, case-insensitive
|
||||||
$hashedContent = hash('md5', $fileContent);
|
$extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
|
||||||
|
if ($extension === '' || !in_array($extension, $allowed_extensions, true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Generate a secure filename using the hashed content
|
// Unguessable storage name. We deliberately do NOT hash file contents:
|
||||||
$secureFilename = $hashedContent . randomString(2) . '.' . $extension;
|
// randomString(32) already guarantees uniqueness, and hashing would mean
|
||||||
|
// reading the whole file into memory (up to 500 MB) for no downstream use.
|
||||||
return $secureFilename;
|
return randomString(32) . '.' . $extension;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user