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.
-
1Please 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 Answers
This has been answered before on this site, in extensive detail. See these questions:
- What are the security risks of letting the users upload content to my site?
- Is it necessary to scan users' file uploads by antivirus?
- Antivirus for scanning anonymous file uploads
- What steps should be taken to validate user uploaded images within an application?
- What are security risks of serving user uploaded files without Content-Disposition?
- Why should I restrict the content type of files be uploaded to my site?
- Is it safe to store and replay user-provided mime types?
- Is it safe to serve any user uploaded file under only white-listed MIME content types?
For general advice relating to web security, OWASP is always a good resource, too.
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.
- 131
- 3
-
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
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 HTTPContent-type
headerfunction 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
.
- 9,797
- 1
- 30
- 50
-
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
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.
- 3,166
- 14
- 25
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.
- 18,278
- 39
- 73
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...
- 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