News:

SMF 2.1.4 has been released! Take it for a spin! Read more.

Main Menu

Only allow specific mime types for attachments

Started by GL700Wing, November 03, 2020, 03:28:25 AM

Previous topic - Next topic

GL700Wing

Although it is possible to configure and check for specific attachment file extensions (eg, jpg, jpeg, pdf, png) the file content/mime type is not checked and as a result any file type can be attached by simply changing the file extension to match one of the allowed extensions.

With a new forum I am setting up there is a requirement to only allow files with specific content/mime types to be attached and I've done this by making the following code changes:

In ./Sources/ManageAttachments.php
Find:
array('check', 'attachmentRecodeLineEndings'),
Add After:
array('check', 'attachmentCheckMimes'),
array('text', 'attachmentMimes', 40),



In ./Sources/Subs-Post.php
Find:
if (!in_array(strtolower(substr(strrchr($attachmentOptions['name'], '.'), 1)), $allowed))
$attachmentOptions['errors'][] = 'bad_extension';
}

Add After:
if (!empty($modSettings['attachmentCheckMimes']))
{
$allowed = explode(',', strtolower($modSettings['attachmentMimes']));
foreach ($allowed as $k => $dummy)
$allowed[$k] = trim($dummy);

if (!in_array(strtolower(substr(strrchr($attachmentOptions['file_type'], '/'), 1)), $allowed))
$attachmentOptions['errors'][] = 'bad_mime';
}



In ./Sources/Post.php
Find:
fatal_error($_FILES['attachment']['name'][$n] . '.<br />' . $txt['cant_upload_type'] . ' ' . $modSettings['attachmentExtensions'] . '.', false);
}

Add After
if (!empty($modSettings['attachmentCheckMimes']))
{
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $_FILES['attachment']['tmp_name'][$n]);
finfo_close($finfo);

if (!in_array($mime, explode(',', strtolower($modSettings['attachmentMimes']))))
fatal_error('<strong>' . $_FILES['attachment']['name'][$n] . '</strong><br /><br />' . sprintf($txt['cant_upload_mime'], $mime) . '</strong>' . $modSettings['attachmentMimes'] . '</strong>', false);
}

Find:
fatal_lang_error('file_too_big', false, array($modSettings['attachmentPostLimit']));
}

Add After:
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $_FILES['attachment']['tmp_name'][$n]);
finfo_close($finfo);


Find:
'approved' => !$modSettings['postmod_active'] || allowedTo('post_attachment'),
Add After:
'file_type' => $mime,

Find:
fatal_error($attachmentOptions['name'] . '.<br />' . $txt['cant_upload_type'] . ' ' . $modSettings['attachmentExtensions'] . '.', false);
}

Add After:
if (in_array('bad_mime', $attachmentOptions['errors']))
{
checkSubmitOnce('free');
fatal_error('<strong>' . $attachmentOptions['name'] . '</strong><br /><br />' . sprintf($txt['cant_upload_mime'], $attachmentOptions['file_type']) . '</strong>' . $modSettings['attachmentMimes'] . '</strong>', false);
}



In ./Themes/default/languages/Post.english.php
Find:
$txt['cant_upload_type'] = 'You cannot upload that type of file. The only allowed extensions are';
Add After:
$txt['cant_upload_mime'] = 'You cannot upload that type of file (ie, "%1$s"). The only allowed file content/mime types are: ';


In ./Themes/default/languages/Admin.english.php
Find:
$txt['attachmentRecodeLineEndings'] = 'Recode line endings in textual attachments';
Add After:
$txt['attachmentCheckMimes'] = 'Check attachment\'s file content/mime type';
$txt['attachmentMimes'] = 'Allowed file content/mime types<div class="smalltext"/>Note: Enter <b>jpeg</b> for JPG and JPEG image files.</div>';
Life doesn't have to be perfect to be wonderful ...

Arantor

Note this only works if you have the finfo extension installed.

GL700Wing

Quote from: Arantor on November 03, 2020, 02:26:24 PM
Note this only works if you have the finfo extension installed.
Thanks - I should have mentioned that.

Also, and in cPanel on my websites, the PHP extension name is shown as 'fileinfo' and it has been available since PHP 5.2 (and it is enabled by default).
Life doesn't have to be perfect to be wonderful ...

Arantor

A surprising number of hosts actually disable this. You'd think they wouldn't but in the same way the JSON encode/decode functions were part of core in 5.2+ and enabled by default, WordPress for years had to backtrack on relying on hosts having it because they just didn't. Some of the worst offenders offload even 'standard' extensions to keep their PHP binaries as lean and efficient as possible.

It's technically both fileinfo and finfo - as per https://www.php.net/manual/en/book.fileinfo.php - I just refer to it as finfo because I write everything using OOP where possible and that's the OOP class name (rather than fileinfo even if it is bundled and activated by ext/fileinfo under the hood)

Advertisement: