Skip to content
This repository has been archived by the owner on May 25, 2023. It is now read-only.

Commit

Permalink
SECURITY: Verify file signatures before image processing.
Browse files Browse the repository at this point in the history
This mitigates potential vulnerabilities in ImageMagick when handling input files other than GIF/JPEG/PNG.
However this does not prevent all potential vulnerabilities with ImageMagick.
It is therefore recommended to disable all non-required ImageMagick coders via policy.xml.

See also:
https://imagetragick.com/
https://www.kb.cert.org/vuls/id/332928
https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=imagemagick
  • Loading branch information
blueimp committed Oct 25, 2018
1 parent 56ebf0f commit fe44d34
Showing 1 changed file with 31 additions and 20 deletions.
51 changes: 31 additions & 20 deletions server/php/UploadHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ class UploadHandler
'image_resize' => 'Failed to resize image'
);

protected const IMAGETYPE_GIF = 1;
protected const IMAGETYPE_JPEG = 2;
protected const IMAGETYPE_PNG = 3;

protected $image_objects = array();

public function __construct($options = null, $initialize = true, $error_messages = null) {
Expand Down Expand Up @@ -114,9 +118,7 @@ public function __construct($options = null, $initialize = true, $error_messages
'min_file_size' => 1,
// The maximum number of files for the upload directory:
'max_number_of_files' => null,
// Defines which files are handled as image files:
'image_file_types' => '/\.(gif|jpe?g|png)$/i',
// Use exif_imagetype on all files to correct file extensions:
// Reads first file bytes to identify and correct file extensions:
'correct_image_extensions' => false,
// Image resolution restrictions:
'max_width' => null,
Expand Down Expand Up @@ -163,7 +165,7 @@ public function __construct($options = null, $initialize = true, $error_messages
'max_width' => 800,
'max_height' => 600
),
*/
*/
'thumbnail' => array(
// Uncomment the following to use a defined directory for the thumbnails
// instead of a subdirectory based on the version identifier.
Expand Down Expand Up @@ -433,9 +435,8 @@ protected function validate($uploaded_file, $file, $error, $index) {
$min_width = @$this->options['min_width'];
$min_height = @$this->options['min_height'];
if (($max_width || $max_height || $min_width || $min_height)
&& preg_match($this->options['image_file_types'], $file->name)) {
&& $this->is_valid_image_file($uploaded_file)) {
list($img_width, $img_height) = $this->get_image_size($uploaded_file);

// If we are auto rotating the image by default, do the checks on
// the correct orientation
if (
Expand All @@ -449,7 +450,6 @@ function_exists('exif_read_data') &&
$img_height = $tmp;
unset($tmp);
}

}
if (!empty($img_width)) {
if ($max_width && $img_width > $max_width) {
Expand Down Expand Up @@ -511,16 +511,15 @@ protected function fix_file_extension($file_path, $name, $size, $type, $error,
preg_match('/^image\/(gif|jpe?g|png)/', $type, $matches)) {
$name .= '.'.$matches[1];
}
if ($this->options['correct_image_extensions'] &&
function_exists('exif_imagetype')) {
switch (@exif_imagetype($file_path)){
case IMAGETYPE_JPEG:
if ($this->options['correct_image_extensions']) {
switch ($this->imagetype($file_path)) {
case self::IMAGETYPE_JPEG:
$extensions = array('jpg', 'jpeg');
break;
case IMAGETYPE_PNG:
case self::IMAGETYPE_PNG:
$extensions = array('png');
break;
case IMAGETYPE_GIF:
case self::IMAGETYPE_GIF:
$extensions = array('gif');
break;
}
Expand Down Expand Up @@ -1063,15 +1062,27 @@ protected function destroy_image_object($file_path) {
}
}

protected function is_valid_image_file($file_path) {
if (!preg_match($this->options['image_file_types'], $file_path)) {
return false;
protected function imagetype($file_path) {
$fp = fopen($file_path, 'r');
$data = fread($fp, 4);
fclose($fp);
// GIF: 47 49 46
if (substr($data, 0, 3) === 'GIF') {
return self::IMAGETYPE_GIF;
}
if (function_exists('exif_imagetype')) {
return @exif_imagetype($file_path);
// JPG: FF D8
if (bin2hex(substr($data, 0, 2)) === 'ffd8') {
return self::IMAGETYPE_JPEG;
}
$image_info = $this->get_image_size($file_path);
return $image_info && $image_info[0] && $image_info[1];
// PNG: 89 50 4E 47
if (bin2hex(@$data[0]).substr($data, 1, 4) === '89PNG') {
return self::IMAGETYPE_PNG;
}
return false;
}

protected function is_valid_image_file($file_path) {
return !!$this->imagetype($file_path);
}

protected function handle_image_file($file_path, $file) {
Expand Down

0 comments on commit fe44d34

Please sign in to comment.