I have been researching securely uploading images, and it has become apparent that actually serving the images is where most of the risk is for rogue PHP files that could compromise the server.
Many are suggesting that having a image processing script e.g getimage.php?i=575748 which would lookup in the database 575748 and actually return myphoto.jpg (whithout the user knowing the location of the origional image) is much more secure.
Can any point me in the right direction of what sort of things I should be implementing in the script? I know setting the content type headers is a must, but is this enough to stop code executing?
Thanks!
This only happens if two conditions are met:
Thwart one of these and the danger disappears. Of course closing both is better.
The database solution aims at disrupting condition #2, but you can also check, when uploading the image, that it is indeed an image using the
getImageSize()function. Or trying to load the image withimageCreateFromJPEG()or other appropriate function.If the object loaded is not an image, just display “Sorry, image is corrupt”. This both protects your users against uploading broken images and you against someone uploading a rogue PHP file (or maybe a copyrighted video or cracked executable or…).
UPDATE: you can also obfuscate an already existing upload-and-download facility:
Say that currently you upload the user image, assign to it a unique ID, save it as
./images/UNIQUEID.jpg, and serve to the userhttp://www.yoursite.com/images/UNIQUEID.jpgas URL..htaccessso that access to./images/whateveris redirected to./images/index.php?ID=whateverindex.phpscript that takes “whatever”, extracts the image ID, and outputs the image.All old URLs will continue to work and appear to directly load the image, but what they’re actually doing is invoke a PHP script that checks for the image and sends it along as a bytestream, without interpreting.
You’ll want to be setting
ETagto the ID,Last-Modifiedtofile_mtime()of the image file, andContent-Lengthto the file size. Also, you may want to check the incoming headerIf-Modified-SinceandIf-None-Match: if the date of the file corresponds to IMS or the IFN value corresponds to the ID, you can send aHTTP/304 Not Modifiedanswer instead of the image, saving considerable bandwidth.