better validation for uploaded/imported image files
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
This commit is contained in:
@@ -28,6 +28,7 @@ namespace Froxlor;
|
|||||||
use Exception;
|
use Exception;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\UI\Form;
|
use Froxlor\UI\Form;
|
||||||
|
use Froxlor\Validate\Validate;
|
||||||
use PDO;
|
use PDO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -159,6 +160,9 @@ class SImExporter
|
|||||||
// re-format the array-key for Form::processForm
|
// re-format the array-key for Form::processForm
|
||||||
foreach ($_data as $key => $value) {
|
foreach ($_data as $key => $value) {
|
||||||
$index_split = explode('.', $key, 3);
|
$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]])) {
|
if (isset($index_split[2]) && $index_split[2] === 'image_data' && !empty($_data[$index_split[0] . '.' . $index_split[1]])) {
|
||||||
$image_data[$key] = $value;
|
$image_data[$key] = $value;
|
||||||
} else {
|
} else {
|
||||||
@@ -190,42 +194,27 @@ class SImExporter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$img_data = base64_decode($value);
|
if (Validate::validateBase64Image($value)) {
|
||||||
$img_filename = Froxlor::getInstallDir() . '/' . str_replace('../', '',
|
$img_data = base64_decode($value);
|
||||||
explode('?', $_data[$index_split[0] . '.' . $index_split[1]], 2)[0]);
|
$img_filename = explode('?', $_data[$index_split[0] . '.' . $index_split[1]], 2)[0];
|
||||||
|
|
||||||
file_put_contents($img_filename, $img_data);
|
$spl = explode('.', $img_filename);
|
||||||
|
$file_extension = strtolower(array_pop($spl));
|
||||||
|
unset($spl);
|
||||||
|
|
||||||
if (function_exists('finfo_open')) {
|
if (!in_array($file_extension, [
|
||||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
'jpeg',
|
||||||
$mimetype = finfo_file($finfo, $img_filename);
|
'jpg',
|
||||||
finfo_close($finfo);
|
'png',
|
||||||
} else {
|
'gif'
|
||||||
$mimetype = mime_content_type($img_filename);
|
])) {
|
||||||
|
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());
|
||||||
}
|
}
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings::Set($index, $value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// all good
|
// all good
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ use Froxlor\PhpHelper;
|
|||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
use Froxlor\System\Cronjob;
|
use Froxlor\System\Cronjob;
|
||||||
use Froxlor\System\IPTools;
|
use Froxlor\System\IPTools;
|
||||||
|
use Froxlor\Validate\Validate;
|
||||||
use PDO;
|
use PDO;
|
||||||
|
|
||||||
class Store
|
class Store
|
||||||
@@ -415,40 +416,30 @@ class Store
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make sure mime-type matches an image
|
// Make sure mime-type matches an image
|
||||||
if (function_exists('finfo_open')) {
|
$image_content = file_get_contents($_FILES[$fieldname]['tmp_name']);
|
||||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
$value = base64_encode($image_content);
|
||||||
$mimetype = finfo_file($finfo, $_FILES[$fieldname]['tmp_name']);
|
if (Validate::validateBase64Image($value)) {
|
||||||
finfo_close($finfo);
|
$img_filename = $_FILES[$fieldname]['name'];
|
||||||
} 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('.', $img_filename);
|
||||||
$spl = explode('.', $_FILES[$fieldname]['name']);
|
$file_extension = strtolower(array_pop($spl));
|
||||||
$file_extension = strtolower(array_pop($spl));
|
unset($spl);
|
||||||
unset($spl);
|
|
||||||
|
|
||||||
if (!in_array($file_extension, [
|
if (!in_array($file_extension, [
|
||||||
'jpeg',
|
'jpeg',
|
||||||
'jpg',
|
'jpg',
|
||||||
'png',
|
'png',
|
||||||
'gif'
|
'gif'
|
||||||
])) {
|
])) {
|
||||||
throw new Exception("Invalid file-extension, use one of: 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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");
|
|
||||||
}
|
|
||||||
|
|
||||||
$save_to = 'img/' . $fielddata['image_name'] . '.' . $file_extension . '?v=' . time();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete file?
|
// Delete file?
|
||||||
|
|||||||
@@ -334,4 +334,40 @@ class Validate
|
|||||||
}
|
}
|
||||||
return false;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user