views:

103

answers:

3
+3  A: 

It's really rather simple. Run all uploaded images through an image filter that is known to be safe. If it kicks back with a "Not an image error", you have shenanigans. (A simple example would be an identity transform, or a JPEG quality normalization technique.) An important point, tho', is to actually use the output from the filter, not the original file.

Williham Totland
Note that WMF's were both images and executables. Which led to malware guys embedding stuff inside valid "images"..but that was a while back.
Chris Lively
+2  A: 

As you mentioned, there's another question that addresses the issue. The author notes that he should be safe as long as he only accepts genuine image files and keeps down the filesize, which is about the only thing you can do. Check extension and MIME type and reject anything that does not match the formats you want. There's still RFI (well, more like LFI here), but as long as you aren't haphazardly including files without performing sanity checks, you should be good to go.

Matchu
+1  A: 

Things you need to consider and watch out for:

File extensions: Webservers use the file extension to determine the MIME-Type sent to the client. You should use a whitelisting of extensions that you allow. In your case this would be image extensions.

LFI: As already mentioned by Matchu, local file inclusion can be an issue. If your application has dynamic includes that allow you to include an arbitrary file, eg. include($_GET['myfile']); it can lead to arbitrary PHP execution. So you need to secure such includes by using basename(). This can even happen with images, since they can contain embedded comments.

MIME-Type-Detection: This is actually not very well known, and there's not much information about it. IE<8 has a feature called MIME-Type-Detection which will, if the Content-Type does not match with the content, try to guess the type by looking at the first 256 bytes. This means, if you have a PNG file called image.gif with a comment at the top that reads <script>alert('hello');</script>, then IE<8 will think it is HTML and execute the JavaScript, leading to an XSS attack.

To prevent this issue for images you can use the approach mentioned by Williham Totland. I would suggest using getimagesize() to detect if the image is valid and to ensure that the extension matches the type.

$image_filename = 'uploaded_image.gif';
$image_extension = substr(strrchr($image_filename, '.'), 1);

$mime_mapping = array('png' => 'image/png', 'gif' => 'image/gif', 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg');
$info = getimagesize($image_filename);

if (!$info) {
    exit('not an image');
}

if ($info['mime'] != $mime_mapping[$image_extension]) {
    exit('wrong extension given');
}

// all checks passed
// image can be saved now

There is an article written about this issue here.

igorw
Note that it's possible to make an file that contains `<script>` that IE will execute as HTML but is still a valid image and will be passed by `getimagesize()`, so the above isn't safe. This is what Williham was talking about with using a processed output image rather than the original file supplied. Whilst it is theoretically possible to create an image that, when filtered/recompressed/saved by a known target function, would result in something containing unsafe HTML content, this is quite an impractical attack.
bobince
Also there are other types you might try to smuggle into an image, in particular Java and Flash code. These allow scripting but do not abide by the exact ‘same origin policy’ that JavaScript does, so by planting a JAR or SWF on a target server it is partially possible to cross-site-script into it from another page. See the ‘GIFAR’ attack for an example of this. For these reasons it is difficult to guarantee that file upload will be ‘safe’ even with precautions. A good response is to put all user-uploaded content on a separate hostname that does not share a security context with the main site.
bobince
IE will only use MIME-Type-Detection if image content and headers don't match, which my implementation checks. The issue is that there is no such signature for PNG images in older versions. And you are right, GIFAR and flash are quite an issue that require a custom serving script. [Possible solution for GIFAR][1]. Flash attacks require the serving script to be in a separate directory and if possible without public filenames. Or your solution, of course. [1]: http://github.com/phpbb/phpbb3/commit/bf59a749c3346ed7341d03946b8ecd0701af9eb8
igorw
I would give unique name to an image, so I guess I will prevent attacks such as XSS.
hey