17

When I try to process file upload, should I run verification based on file MIME type or file-extension?

What are Pros & cons of these 2 ways of file validating?

And, Any other security issues should i be concerned of?

In these days I was relying on MIME type but the answer with most up-votes in this post

File upload issues in PHP says:

Never rely on the MIME type submitted by the browser!

Community
  • 1
  • 1
Shafiul
  • 2,832
  • 9
  • 37
  • 55
  • 3
    Never by file extension. – N.B. Sep 08 '11 at 14:18
  • 1
    here is what I found http://stackoverflow.com/questions/7317083/php-image-upload-security-approach http://stackoverflow.com/questions/3644138/secure-user-image-upload-capabilities-in-php http://stackoverflow.com/questions/4166762/php-image-upload-security-check-list – ajreal Sep 08 '11 at 14:21
  • 1
    Both are good enough for validation. Not if it's for security enforcement however. (No, not the same thing). And even a valid file format may contain malicious payloads; so normalize content and extension if you can, and adapt upload directory configuration in any case. – mario Sep 08 '11 at 14:22
  • 1
    A false feeling of safety is more dangerous than acknowledged vulnerability. – Your Common Sense Sep 08 '11 at 14:54

4 Answers4

36

Okay, so to all the geniouses here yapping something about "SCREW EXTENSIONS, CHECK MIME! FILEINFO RLZ!", I've prepared some tutorial:

  1. Download this pretty php logo I drew
  2. View it. Pretty nice, isn't it?
  3. Rename it to whatever_you_like.php
  4. Put it through all your awesome mime type/whatever checkers
  5. Run it

In conclusion, you should NEVER EVER EVER rely on MIME type. You web server doesn't care about MIME type, it determines what to do by EXTENSION, the ultimately downvoted @Col. Shrapnel's answer is actually right. Any information provided to you by something checking MIME is absolutely irrelevant to your webserver when it comes to execution.

EDIT: the not-as-uncommon-code-as-you'd-want-it-to-be that opens a website to this type of attack:

<?php

$mimetype = mime_content_type($_FILES['file']['tmp_name']);
if(in_array($mimetype, array('image/jpeg', 'image/gif', 'image/png'))) {
   move_uploaded_file($_FILES['file']['tmp_name'], '/whatever/something/imagedir/' . $_FILES['file']['name']);
   echo 'OK';

} else {
    echo 'Upload a real image, jerk!';
}
Jehy
  • 4,729
  • 1
  • 38
  • 55
cypher
  • 6,822
  • 4
  • 31
  • 48
2

In order to accurately determine what has been uploaded, you don't check for the file extension nor for the mime type sent by browser.

On *nix environment, you've got the utility for checking the mime type of a given file, usually located in magic.mime file (/usr/share/magic.mime or something similar, depending on your setup).

Copy/paste from the magic.mime so you see how it works in a nutshell:

# Magic data for KMimeMagic (originally for file(1) command)
#
# Note on adding additional MIME types:
#
# [RFC2045,RFC2046] specifies that Content Types, Content Subtypes, Character
# Sets, Access Types, and conversion values for MIME mail will be assigned and
# listed by the IANA.
# http://www.iana.org/assignments/media-types/
#
# Any unregistered file type should be listed with a preceding x-, as in
# application/x-foo (RFC2045 5.1), or a x., as in application/x.foo (RFC4288
# 4.3).  Any non x-prefixed type should be registered with IANA and listed at
# the above address.  Any other behavior is a MIME standards violation!
#
# It is preferred that when a registered MIME type exists, that
# the registered Content-Type and Subtype be used to refer to a file of
# that type, so don't use application/x-zip when application/zip is
# registered.
#
# If an active RFC suggests that a MIME registration for a new type is in
# progress, make a note of it pointing to that RFC.
#
# The format is 4-5 columns:
#    Column #1: byte number to begin checking from, ">" indicates continuation
#    Column #2: type of data to match
#    Column #3: contents of data to match
#    Column #4: MIME type of result
#    Column #5: MIME encoding of result (optional)

I'll link you with a link that'll help you in further implementation in PHP (literally 2 lines of code once you're done).

If you can't make it work after all of this, post here in comments and I'll provide full code needed to safely detect what has been uploaded.

Fileinfo

N.B.
  • 13,688
  • 3
  • 45
  • 55
  • so, what's wrong if I won't use this magic? what is attack scenario? – Your Common Sense Sep 08 '11 at 14:58
  • and, also please read the latter comment under our friend Chris' answer. that's quite interesting for you – Your Common Sense Sep 08 '11 at 14:59
  • 2
    @Col. Shrapnel - I didn't say anything's wrong if you don't use it. I've been using this method for quite some time and I never, ever had issues with receiving wrong mime type if I changed the file extension. If someone wants to go with file ext. / browser reported mime type detection - go ahead, it really won't bother me in the end :) just sharing my experience and methods used. – N.B. Sep 08 '11 at 15:08
  • 1
    you constantly fail to answer my questions. Only you can do is to run around screaming "Danger!! Danger!!", but fail to explain what particular danger you're talking about. – Your Common Sense Sep 08 '11 at 15:18
  • 2
    @Col. Shrapnel - We are not here to answer your questions. Also, it strikes me that you are taking this all too personally, being rather abrasive about it, and generally not being very friendly or professional. I hate to even make this comment, but your attitude here is really alarming. Please back off a little. If you are right, support it with objective facts, not left-handed insults and sarcasm. Sorry to the rest for intruding these comments on the discussion here, but I felt it needed to be said. – Chris Baker Sep 08 '11 at 15:27
  • 1
    @Chris `We are not here to answer your questions.` - that's sad but true. Nobody wants to stop and think. – Your Common Sense Sep 08 '11 at 15:31
  • @Col. Shrapnel - I'm deliberately not mentioning danger because I've to explain in what under circumstances "danger" can occur, which means that x amount of "tenants" as you called people at SO will reply with counter-argument. Can extension be changed easily - yes it can. Can browser mime-type be changed easily - yes it can. Why rely on methods that **might** be spoofed by malicious user if you can have bullet proof solution that works? – N.B. Sep 08 '11 at 15:37
  • "magic bytes" might be spoofed as well. Its a matter what you gonna do with this file, not its contents. – Your Common Sense Sep 08 '11 at 15:41
  • @N.B. you are **completely** ignoring that your web server doesn't give a ... about mime. – cypher Sep 08 '11 at 15:45
2

None is appropriate for accurately finding out the type of a file. The reasons are - * Extension - a user can easily change the extension by just renaming the file. * Mime type - To change the mime type, some add-on/extension can do that as it is coming from client side (so can be changed before sending to server), not generated by server.

Now for verification, the answer of the question depends on why you want to verify the file type.

Most of the time we need to make sure the uploaded file should not get executed. For this reason you need to be sure about how your server handles/executes files. - If your server checks extensions for verification, you also need to verify you are not storing a file with extension which can get executed. - If your server use mime-types, beware of the fact that the mime-type sent by the client and the mime-type used by the server for the same file can be different. So use the same logic your server use to find out the mime-type.

Md Enzam Hossain
  • 1,246
  • 1
  • 11
  • 12
1

Mime-type is not reliable source, because it sends from browser (also anyone can create HTTP request manually). PHP do not checked equivalence of extension and mine-type (http://ru.php.net/manual/en/features.file-upload.post-method.php). You can accent HTTP request with filename "image.php" and mime-type "image/gif".

Use always verification by extension if you want save uploaded file to HDD and give public access to this file later.

Mihail H.
  • 1,555
  • 16
  • 18
  • 1
    The extension is completely arbitrary, far less reliable than the browser mime-type. If you're willing to question the browser mime-type, then you should **definitely** question the extension: the extension comes from the user! – Chris Baker Sep 08 '11 at 14:43
  • Web server (apache, etc.) detects how to handle file by extension. If you accept HTTP request with filename "image.php" and mime-type "image/gif" and save to public directory on HDD file "image.php" (with .php extension), apache will be handle this file like php sсript (hacker can upload this file, request it after uploading and get full access to the server). – Mihail H. Sep 08 '11 at 14:53
  • @mkharitonov you have to add a @ in front of person you want to talk. they'll be notified of your reply then – Your Common Sense Sep 08 '11 at 15:37