Skip to content
Permalink
Browse files Browse the repository at this point in the history
better validation for uploaded/imported image files
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
  • Loading branch information
d00p committed Mar 8, 2023
1 parent c56e0b9 commit f36bc61
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 68 deletions.
59 changes: 24 additions & 35 deletions lib/Froxlor/SImExporter.php
Expand Up @@ -28,6 +28,7 @@
use Exception;
use Froxlor\Database\Database;
use Froxlor\UI\Form;
use Froxlor\Validate\Validate;
use PDO;

/**
Expand Down Expand Up @@ -159,6 +160,9 @@ public static function import($json_str = null)
// re-format the array-key for Form::processForm
foreach ($_data as $key => $value) {
$index_split = explode('.', $key, 3);
if (!isset($current_settings[$index_split[0]][$index_split[1]])) {
continue;
}
if (isset($index_split[2]) && $index_split[2] === 'image_data' && !empty($_data[$index_split[0] . '.' . $index_split[1]])) {
$image_data[$key] = $value;
} else {
Expand Down Expand Up @@ -190,42 +194,27 @@ public static function import($json_str = null)
}
}

$img_data = base64_decode($value);
$img_filename = Froxlor::getInstallDir() . '/' . str_replace('../', '',
explode('?', $_data[$index_split[0] . '.' . $index_split[1]], 2)[0]);

file_put_contents($img_filename, $img_data);

if (function_exists('finfo_open')) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimetype = finfo_file($finfo, $img_filename);
finfo_close($finfo);
} else {
$mimetype = mime_content_type($img_filename);
}
if (empty($mimetype)) {
$mimetype = 'application/octet-stream';
}
if (!in_array($mimetype, ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'])) {
@unlink($img_filename);
throw new Exception("Uploaded file is not a valid image");
}

$spl = explode('.', $img_filename);
$file_extension = strtolower(array_pop($spl));
unset($spl);

if (!in_array($file_extension, [
'jpeg',
'jpg',
'png',
'gif'
])) {
@unlink($img_filename);
throw new Exception("Invalid file-extension, use one of: jpeg, jpg, png, gif");
if (Validate::validateBase64Image($value)) {
$img_data = base64_decode($value);
$img_filename = explode('?', $_data[$index_split[0] . '.' . $index_split[1]], 2)[0];

$spl = explode('.', $img_filename);
$file_extension = strtolower(array_pop($spl));
unset($spl);

if (!in_array($file_extension, [
'jpeg',
'jpg',
'png',
'gif'
])) {
throw new Exception("Invalid file-extension, use one of: jpeg, jpg, png, gif");
}
$img_filename = 'img/' . bin2hex(random_bytes(16)) . '.' . $file_extension;
file_put_contents(Froxlor::getInstallDir() . '/' . $img_filename, $img_data);
$img_index = $index_split[0].'.'.$index_split[1];
Settings::Set($img_index, $img_filename . '?v=' . time());
}

Settings::Set($index, $value);
}
}
// all good
Expand Down
57 changes: 24 additions & 33 deletions lib/Froxlor/Settings/Store.php
Expand Up @@ -36,6 +36,7 @@
use Froxlor\Settings;
use Froxlor\System\Cronjob;
use Froxlor\System\IPTools;
use Froxlor\Validate\Validate;
use PDO;

class Store
Expand Down Expand Up @@ -415,40 +416,30 @@ public static function storeSettingImage($fieldname, $fielddata)
}

// Make sure mime-type matches an image
if (function_exists('finfo_open')) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimetype = finfo_file($finfo, $_FILES[$fieldname]['tmp_name']);
finfo_close($finfo);
} else {
$mimetype = mime_content_type($_FILES[$fieldname]['tmp_name']);
}
if (empty($mimetype)) {
$mimetype = 'application/octet-stream';
}
if (!in_array($mimetype, ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'])) {
throw new \Exception("Uploaded file is not a valid image");
}

// Determine file extension
$spl = explode('.', $_FILES[$fieldname]['name']);
$file_extension = strtolower(array_pop($spl));
unset($spl);

if (!in_array($file_extension, [
'jpeg',
'jpg',
'png',
'gif'
])) {
throw new Exception("Invalid file-extension, use one of: jpeg, jpg, png, gif");
}

// Move file
if (!move_uploaded_file($_FILES[$fieldname]['tmp_name'], $path . $fielddata['image_name'] . '.' . $file_extension)) {
throw new Exception("Unable to save image to img folder");
$image_content = file_get_contents($_FILES[$fieldname]['tmp_name']);
$value = base64_encode($image_content);
if (Validate::validateBase64Image($value)) {
$img_filename = $_FILES[$fieldname]['name'];

$spl = explode('.', $img_filename);
$file_extension = strtolower(array_pop($spl));
unset($spl);

if (!in_array($file_extension, [
'jpeg',
'jpg',
'png',
'gif'
])) {
throw new Exception("Invalid file-extension, use one of: jpeg, jpg, png, gif");
}
$filename = bin2hex(random_bytes(16)) . '.' . $file_extension;
// Move file
if (!move_uploaded_file($_FILES[$fieldname]['tmp_name'], $path . $filename)) {
throw new Exception("Unable to save image to img folder");
}
$save_to = 'img/' . $filename . '?v=' . time();
}

$save_to = 'img/' . $fielddata['image_name'] . '.' . $file_extension . '?v=' . time();
}

// Delete file?
Expand Down
36 changes: 36 additions & 0 deletions lib/Froxlor/Validate/Validate.php
Expand Up @@ -334,4 +334,40 @@ public static function validateSqlInterval(string $interval = ''): bool
}
return false;
}

/**
* validates whether a given base64 string decodes to an image
*
* @param string $base64string
* @return bool
* @throws Exception
*/
public static function validateBase64Image(string $base64string) {

if (!extension_loaded('gd')) {
Response::standardError('phpgdextensionnotavailable', null, true);
}

// Decode the base64 string
$data = base64_decode($base64string);

// Create an image from the decoded data
$image = @imagecreatefromstring($data);

// Check if the image was created successfully
if (!$image) {
return false;
}

// Get the MIME type of the image
$mime = image_type_to_mime_type(getimagesizefromstring($data)[2]);

// Check if the MIME type is a valid image MIME type
if (strpos($mime, 'image/') !== 0) {
return false;
}

// If everything is okay, return true
return true;
}
}

0 comments on commit f36bc61

Please sign in to comment.