Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 100 additions & 5 deletions ProcessMaker/Http/Controllers/Api/ProcessRequestFileController.php
Original file line number Diff line number Diff line change
Expand Up @@ -289,14 +289,14 @@ public function store(Request $laravel_request, FileReceiver $receiver, ProcessR
} catch (FileIsTooBig $e) {
return response()->json([
'errors' => [
'file' => ['file may not be greater than ' . (config('media-library.max_file_size') / 1024) . ' kilobytes']
]
'file' => ['file may not be greater than ' . (config('media-library.max_file_size') / 1024) . ' kilobytes'],
],
], 422);
} catch (Exception $e) {
return response()->json([
'errors' => [
'message' => $e->getMessage()
]
'message' => $e->getMessage(),
],
], 500);
}
}
Expand Down Expand Up @@ -440,15 +440,110 @@ public function destroy(Request $laravel_request, ProcessRequest $request, $file
return response([], 204);
}

/**
* Validate uploaded file for security and type restrictions
*
* @param UploadedFile $file
* @param array $errors
* @return array
*/
private function validateFile(UploadedFile $file, &$errors)
{
if (strtolower($file->getClientOriginalExtension() === 'pdf')) {
// Explicitly reject archive files for security
$this->rejectArchiveFiles($file, $errors);

// Validate file extension if enabled
if (config('files.enable_extension_validation', true)) {
$this->validateFileExtension($file, $errors);
}

// Validate MIME type vs extension if enabled
if (config('files.enable_mime_validation', true)) {
$this->validateExtensionMimeTypeMatch($file, $errors);
}

// Validate specific file types (e.g., PDF for JavaScript content)
if (strtolower($file->getClientOriginalExtension()) === 'pdf') {
$this->validatePDFFile($file, $errors);
}

return $errors;
}

/**
* Explicitly reject archive files for security reasons
*
* @param UploadedFile $file
* @param array $errors
* @return void
*/
private function rejectArchiveFiles(UploadedFile $file, &$errors)
{
$dangerousExtensions = config('files.dangerous_extensions');

$fileExtension = strtolower($file->getClientOriginalExtension());

if (in_array($fileExtension, $dangerousExtensions)) {
$errors['message'] = __('Uploaded file type is not allowed');

return;
}

// Also check MIME types for archive files
$dangerousMimeTypes = config('files.dangerous_mime_types');

$fileMimeType = $file->getMimeType();

if (in_array($fileMimeType, $dangerousMimeTypes)) {
$errors['message'] = __('Uploaded mime file type is not allowed');
}
}

/**
* Validate that file extension matches the MIME type
*
* @param UploadedFile $file
* @param array $errors
* @return void
*/
private function validateExtensionMimeTypeMatch(UploadedFile $file, &$errors)
{
$fileExtension = strtolower($file->getClientOriginalExtension());
$fileMimeType = $file->getMimeType();

// Get extension to MIME type mapping from configuration
$extensionMimeMap = config('files.extension_mime_map');

// Check if extension exists in our map
if (!isset($extensionMimeMap[$fileExtension])) {
$errors['message'] = __('File extension not allowed');

return;
}

// Check if MIME type matches any of the expected types for this extension
if (!in_array($fileMimeType, $extensionMimeMap[$fileExtension])) {
$errors['message'] = __('The file extension does not match the actual file content');
}
}

/**
* Validate file extension against allowed extensions
*
* @param UploadedFile $file
* @param array $errors
* @return void
*/
private function validateFileExtension(UploadedFile $file, &$errors)
{
$allowedExtensions = config('files.allowed_extensions');
$fileExtension = strtolower($file->getClientOriginalExtension());

if (!in_array($fileExtension, $allowedExtensions)) {
$errors['message'] = __('File extension not allowed');
}
}

private function validatePDFFile(UploadedFile $file, &$errors)
{
$text = $file->get();
Expand Down
138 changes: 138 additions & 0 deletions config/files.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?php

return [
/*
|--------------------------------------------------------------------------
| File Upload Configuration
|--------------------------------------------------------------------------
|
| This file contains configuration options for file uploads including
| allowed file extensions and MIME types for security validation.
|
*/

/*
|--------------------------------------------------------------------------
| Allowed File Extensions
|--------------------------------------------------------------------------
|
| List of file extensions that are allowed to be uploaded.
| Only files with these extensions will be accepted.
| Archive formats (.zip, .rar, .tar, .7z) are explicitly NOT allowed for security.
|
*/
'allowed_extensions' => [
// Documents
'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx',
'txt', 'csv',

// Images
'jpg', 'jpeg', 'png', 'gif', 'svg',

// Audio
'mp3',

// Video
'mp4',
],
/*
|--------------------------------------------------------------------------
| Extension to MIME Type Mapping
|--------------------------------------------------------------------------
|
| An associative array that maps each allowed file extension to one or more
| corresponding MIME types. This provides a strong validation to ensure that
| a file's content type (MIME type) matches its declared extension,
| preventing malicious files (like a script disguised as an image) from being uploaded.
|
*/
'extension_mime_map' => [
// Documents
'pdf' => ['application/pdf'],
'doc' => ['application/msword'],
'docx' => ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
'xls' => ['application/vnd.ms-excel'],
'xlsx' => ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
'ppt' => ['application/vnd.ms-powerpoint'],
'pptx' => ['application/vnd.openxmlformats-officedocument.presentationml.presentation'],
'txt' => ['text/plain'],
'csv' => ['text/csv', 'application/csv'],

// Audio
'jpg' => ['image/jpeg'],
'jpeg' => ['image/jpeg'],
'png' => ['image/png'],
'gif' => ['image/gif'],
'svg' => ['image/svg+xml'],

// Audio
'mp3' => ['audio/mpeg'],

// Video
'mp4' => ['video/mp4'],
],

/*
|--------------------------------------------------------------------------
| Enable MIME Type Validation
|--------------------------------------------------------------------------
|
| Whether to enable MIME type validation against allowed_mime_types list
| AND validate that MIME type corresponds to file extension using extension_mime_map.
| This provides comprehensive validation to prevent malicious files.
| Recommended to keep this enabled for security.
|
*/
'enable_mime_validation' => env('ENABLE_MIME_VALIDATION', true),

/*
|--------------------------------------------------------------------------
| Enable Extension Validation
|--------------------------------------------------------------------------
|
| Whether to enable basic file extension validation against allowed_extensions list.
| This validates that the file extension is in the allowed list.
| Recommended to keep this enabled for security.
|
*/
'enable_extension_validation' => env('ENABLE_EXTENSION_VALIDATION', true),

/*
|--------------------------------------------------------------------------
| Security Dangerous File Extensions
|--------------------------------------------------------------------------
|
| Archive formats (.zip, .rar, .tar, .7z, .gz, etc.) are explicitly
| NOT allowed for security reasons. These file types can contain
| malicious content and are blocked by default.
|
*/
'dangerous_extensions' => [
'zip', 'rar', '7z', 'tar', 'gz', 'bz2', 'xz', 'lzma',
'cab', 'ar', 'iso', 'dmg', 'pkg', 'deb', 'rpm',
],

/*
|--------------------------------------------------------------------------
| Security Dangerous MIME Types
|--------------------------------------------------------------------------
|
| A list of MIME types associated with archives and executables.
| This provides an additional layer of security to prevent the upload of
| compressed files or other potentially dangerous content, even if their
| file extension has been tampered with.
|
*/
'dangerous_mime_types' => [
'application/zip',
'application/x-rar-compressed',
'application/x-7z-compressed',
'application/x-tar',
'application/gzip',
'application/x-bzip2',
'application/x-xz',
'application/x-lzma',
'application/vnd.ms-cab-compressed',
'application/x-iso9660-image',
],
];
4 changes: 4 additions & 0 deletions resources/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,7 @@
"File Access": "File Access",
"File crt": "File crt",
"File Download": "File Download",
"File extension not allowed": "File extension not allowed",
"File ID does not exist": "File ID does not exist",
"File key": "File key",
"File Manager": "File Manager",
Expand Down Expand Up @@ -2198,6 +2199,7 @@
"The field unter validation must be after or equal to the given field.": "The field unter validation must be after or equal to the given field.",
"The field unter validation must be before or equal to the given field.": "The field unter validation must be before or equal to the given field.",
"The field unter validation must be before the given date.": "The field unter validation must be before the given date.",
"The file extension does not match the actual file content": "The file extension does not match the actual file content",
"The file is processing. You may continue working while the log file compiles.": "The file is processing. You may continue working while the log file compiles.",
"The file you are importing was made with an older version of ProcessMaker. Advanced import is not available. All assets will be copied.": "The file you are importing was made with an older version of ProcessMaker. Advanced import is not available. All assets will be copied.",
"The following items should be configured to ensure your process is functional.": "The following items should be configured to ensure your process is functional.",
Expand Down Expand Up @@ -2443,6 +2445,8 @@
"Upload": "Upload",
"Uploaded By": "Uploaded By",
"Uploaded": "Uploaded",
"Uploaded file type is not allowed.": "Uploaded file type is not allowed.",
"Uploaded mime file type is not allowed": "Uploaded mime file type is not allowed",
"Uploading...": "Uploading...",
"Uppercase characters": "Uppercase characters",
"URI": "URI",
Expand Down
Loading
Loading