Checking for mime type in php is pretty easy but as far as I know mime can be spoofed. The attacker can upload a php script with for example jpeg mime type. One thing that comes to mind is to check the file extension of the uploaded file and make sure it matches the mime type. All of this is assuming the upload directory is browser accessible.
Question: Are there any other techniques for preventing "bad files" from getting in with mime type spoofing?
Short answer: No.
Longer answer:
Comparing the extension and making sure that it matches the MIME type doesn't really prevent anything. As was said in the comments, it's even easier to modify a file extension. MIME type and extension are only to be meant as hints, there's no inherent security in them.
Ensuring that incoming files do no harm is very dependent on what your purpose for them is going to be. In your case I understood that you are expecting images. So what you could do is perform some sanity checks first: scan the first couple of bytes to see if the files contain the relevant image header signatures - all relevant image formats have these.
The "signature headers" help you to decide what kind of image format a file tries to impersonate. In a next step you could check if the rest of the contents are compliant with the underlying image format. This would guarantee you that the file is really an image file of that specific format.
But even then, the file could be carefully crafted in a way that when you display the image, a popular library used to display that image (e.g. libpng etc.) would run into a buffer overflow that the attacker found in that library.
Unfortuantely there's no way to actively prevent this besides not allowing any input from the client side at all.
Caution - this answer is now obsolete
The documentation for getimagesize explicitly states "Do not use getimagesize() to check that a given file is a valid image.
In case of Images
- Check the extension with a list of allowed ones (ex. ".jpg", ".jpeg", ".png")
- Check the uploaded file itself by running getimagesize on the file, it will return FALSE if it's not an image.
Other types of upload
- Check the allowed extensions (ex. ".pdf")
- Check that the mime type of the file corresponds to the extension
Sample code:
function getRealMimeType($filename) {
$finfo = new finfo(FILEINFO_MIME, "/usr/share/misc/magic");
if (!$finfo) {
echo "Opening fileinfo database failed";
return "";
}
return $finfo->file($filename);
}
See finfo_file documentation.
Check the extension.
<?php
$okFiles = array('jpg', 'png', 'gif');
$pathInfo = pathinfo($filename);
if(in_array($pathInfo['extension'], $okFiles)) {
//Upload
}
else {
//Error
}
?>
You can also - like you said - check if the extension match the MIME type, but it's much more easy to just check the extension.
Btw why do you care about the MIME type?