How can I protect a PHP image upload script from exploits?
I've created (using a script and some help from Stack and some help from friends; I know very little about PHP) a simple page for a local non-profit publication where people can upload photos.
I'm not great with security (from a basis of ignorance, not deliberate negligence) but I've taken the following steps to protect this page:
• the PHP script is set to only accept .jpg, .png and .tif files for upload; • the subfolder that it saves the form content to has permissions set at 700, and the subfolder it saves uploaded photos to has permissions set at 700; • according to documentation, my host has the following configuration to ensure that only .php files run as .php:
<FilesMatch \.php$> SetHandler php52-fcgi </FilesMatch>
• I’ve put an .htaccess file in the relevant (main and saved content) folders:
RemoveHandler .php RemoveHandler .inc RemoveHandler .pl RemoveHandler .cgi RemoveHandler .py RemoveHandler .fcgi
Overnight, however, somebody found this test page and submitted what seems to be a perfectly benign test message and small .jpg. This is a private test page with a non-intuitive URL that only I and about three other people know about; none of the others sent this test.
This obviously has me worried that there's something hinky going on, and I'm worried that I don't know enough about security to make sure this page is safe.
Is there something obvious that I'm missing?
When dealing with uploaded you should keep in mind that all the data you can find in the $_FILES array can be faked. It's traveling through HTTP so it's pretty easy to give the image/jpg mime to an executable file for exemple.
1- Check the true mime
PHP come with some function to check the real mime of a file. For that you should use fileinfo
$finfo = new finfo(FILEINFO_MIME, "/usr/share/misc/magic"); $filename = "/var/tmp/afile.jpg"; echo $finfo->file($filename);
2- Check the image's properties
You apparently want to upload only image , so the received file must have a width and a height :
Use getImageSize() to get all the required information about the image. If it return false , the file is probably not an image and you can delete it. getImageSize can also give you a mime type , but i don't know if it can be trusted.
2.5- Reprocess image
As suggested by user628405 , reprocessing the image with GD is probably the more secure thing to do.
$img = imagecreatefrompng('vulnerable.png'); imagepng($img, 'safe.png');
Obviously it has to be adapted according to the image type. See all the imagecreatefrom* in php documentation.
3- Upload folder In addition of what you have already done :
Make sure your upload folder is not available from the web. Validate the uploaded file then move it to an other folder if needed and rename the file. It will prevent hacker from executing a malicious file (can't execute it if it can't be reached by an url).
Further reading : https://www.owasp.org/index.php/Unrestricted_File_Upload