3

I want my users to be able to upload a photo. Currently I am not checking the uploaded photo for problems of any kind, although I do limit the size to 32k. Is there any way for me to check uploaded image files for malware? For instance, is there a server out there running ClamAV that I can access from PHP? Thanks.

Frank E
  • 113
  • 1
  • 1
  • 3
  • 1
    Please use search. This question has been answered multiple times on this site. For instance, this is covered by http://security.stackexchange.com/q/9317/971 and http://security.stackexchange.com/q/23459/971 and should probably be closed as a duplicate, unless you want to edit the question to make it somehow different. – D.W. Jan 10 '13 at 02:39
  • Take a look at [php-clamav](http://php-clamav.sourceforge.net/ "php-clamav"). It should be as simple as installing and calling cl_scanfile(). – Motoma Jan 08 '13 at 15:15

6 Answers6

3

A good and popular practice is to check if the uploaded image is really an image and not something else. Validating an image is more secure than scanning with an antivirus.

The getimagesize() function will determine the size of any given image file and return the dimensions along with the file type and a height/width text string to be used inside a normal HTML IMG tag and the correspondent HTTP content type. The function supports many image formats.

You can use getimagesize() to accomplish multiple things at once:

  • Validate that the file is an image
  • Only allow some image types
  • Only allow desired sizes
  • Determine the MIME type of the image which can be used to deliver images with the correct HTTP Content-type header

    function is_image($path)
        {
        $a = getimagesize($path);
        $image_type = $a[2];
    
        if (in_array($image_type , array(IMAGETYPE_GIF , IMAGETYPE_JPEG ,IMAGETYPE_PNG , IMAGETYPE_BMP)))
        {
            return true;
        }
        return false;
    }
    
  • $array[0] and $array[1] are the width and height of the image.

  • $array[2] has the image type.

Note that MPEG videos are detected as IMAGETYPE_ICO.

Cristian Dobre
  • 9,837
  • 1
  • 31
  • 51
  • I think this is bad advice. What's more important is to check the MIME type and make sure the proper MIME type is provided when you serve the file to others, and that you turn off content-type sniffing. I strongly suspect that it would be possible to construct a file that `getimagesize()` thinks is an image but that IE6 or IE7 thinks is some dangerous MIME type (thanks to IE6/IE7's content-sniffing algorithm), particularly if you don't serve a valid MIME type when it is downloaded by others. But see answers I've linked to more for a more thorough treatment of what defenses you should use. – D.W. Jan 10 '13 at 02:43
  • *"It is very difficult to produce a valid image that is also malware or dangerous."* - You provide no evidence for this claim, and I am skeptical of it. – D.W. Jan 10 '13 at 02:44
  • It is quite easy to produce a GIF that's also executable by adding PHP to the comment field. What you need to check can depend on the context. As an example, as Apache will execute files based on extension (and penultimate extension), either make sure the extensions are safe for use or limit handlers in the upload folder. – Heine Jan 10 '13 at 11:33
  • I agree that my answer may sound like a **solution** to dangerous uploads. I know it is not and I tried to convey that. I will edit and tone it down. I still think that using the information from `getimagesize()` is better than AV scanning. – Cristian Dobre Jan 10 '13 at 16:59
3

I think that the best approach would be to use a combined solution:

  • Scan the file using an antivirus
  • Check the MIME type of the file
  • Perform the file size check that Cristi described here
  • Load the uploaded file into an image library and save it again (You may be already doing this if you are resizing the images)

By using all of these checks, the possibility of a successful attack would a lot smaller.

Dinu
  • 3,186
  • 16
  • 25
3

Best I can think for PHP is to re-create the image, for example:

$src_file = '/your/tmp/image.tmp';
$dest_file = '/desired/file/location/img.jpg';
$img_quality = 70;

$im = imagecreatefromstring(file_get_contents($src_file));
$im_w = imagesx($im);
$im_h = imagesy($im);
$tn = imagecreatetruecolor($im_w, $im_h);
imagecopyresampled ( $tn , $im, 0, 0, 0, 0, $im_w, $im_h, $im_w, $im_h );
imagejpeg($tn,$dest_file,$img_quality);

Then delete the originally uploaded image and keep your resized copy.

  • Here is what I don't understand about this script. If you are "copying" the file in the first place, aren't you copying "everything"? What difference does it make weather you delete the old one or not after that? – samayo Dec 03 '13 at 01:44
  • @Qǝuoɯᴉs It does not copy the image, it re-creates it. Re-sizing it would also be a good idea and would result in an entirely different image that the user will consider the same. – Timo Huovinen Dec 03 '13 at 07:38
1

As Christian says, ithe best solution is to whitelist and verify the file type - however any file which has uncompressed metadata can potentially be an avenue for attacking a webserver. Strip the metadata.

Invoking the virus checker synchronously from the web request is a very bad idea in terms of performance, stability and availability. While the default upload handler in PHP sensibly puts files out of the way and forces you to move them before the request completes - this means that you'll have to copy the file once more after you virus scan it.

symcbean
  • 18,418
  • 40
  • 74
1

Not a complete answer* but one way to filter out unwanted content would be to use PHP's image manipulation functions to transpose the uploaded image into a new image and then save that, rather than the uploaded data. A bit like taking a screenshot of a picture rather than just saving the picture directly.

*= Or the best solution, or easiest...

John U
  • 367
  • 1
  • 6
  • If the originally uploaded photo contained any malware, you've probably just managed to infect your web server with it by reading it in your image processor. How sure can you be that the malware contained in the photo wasn't targeting exactly your web server by exploiting any security holes in the image processing library used? – TildalWave Feb 09 '13 at 01:55
  • @TildalWave - I never said it was perfect, but hopefully image processing routines would have even less cause/opportunity to accidentally execute image data as code. – John U Feb 11 '13 at 10:19
  • Well it just so happens that the fastest of them also have the highest number of know exploits. Take for example GDI+ libraries from Microsoft. Extremely fast in loading various image formats (and I do use them), but relatively easily exploitable as well. There are ways to protect even these libraries, but I wouldn't know how to address that in PHP, as I compile my CGIs and try to avoid PHP, especially for security and performance reasons. I didn't rate your answer, I just thought it should be mentioned, that most of these libraries have known exploits. Some pretty bad ones, too. – TildalWave Feb 11 '13 at 18:48