Thread: File Upload Security Tips

  1. #1
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665

    File Upload Security Tips

    Alright, I'm convinced you guys know everything so I figure this is a good place to start.

    How do I make sure secure file uploads can be done with PHP?

    Immediate joke answer : Don't use PHP.

    Ha, ha, ha, ha!

    Now that that's out of the way, for real, how do I do this?

    I've heard using any of the PHP $_FILE stuff is useless because the client can fake it all.

    Some of the tips I've seen are, move uploaded files to outside of the web root. I'm on Ubuntu so my web root is /var/www/. I've heard I should instead upload files to some random other file not contained by /var/www. Sounds fair enough.

    I've also heard that you should use a randomly generate filename and serve the requested uploaded documents using a script file that I've defined.

    Are these good tips? Is there anything I should be aware of? I've heard that checking MIME types can be tricked and apparently, JPGs are like the most threatening thing in the entire world.

    Edit :

    I do have a whitelist of file types I want to allow too.

    For example, XML, all images except GIF, DITA, DITAMAP and I think that's about it.

    I've seen that one should use a database to map the random name to the "real" name of the file. This way I can write a separate script that can ping the database for the randomly generated filename and display the "real" name.
    Last edited by MutantJohn; 09-04-2015 at 02:11 PM.

  2. #2
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    O_o

    You'll find that nearly all servers allowed to execute any code can be somehow tricked into executing malicious code.

    The best advice I can give is "Do not use a blacklist method. Do use a whitelist method.".

    I know you said you had a whitelist for types, but you should limit basically every aspect with whitelists instead of blacklists.

    I don't care if you try blacklisting every problematic MIME, extensions, and header. I will eventually find a problematic combination you've missed if I were to become interested in a focused attack.

    I'd obviously recommend you tick all the known boxes:

    $): You should upload to a directory marked as limiting as much access as is possible.
    $): You should upload to a directory outside of server root directory.
    $): You should prevent the server from serving anything but whitelisted content from the upload directory by both MIME and extension.
    $): You should check and then confirm that any whitelisted content allowable in the upload directory has an associated MIME and extension handler to prevent the server from using a default handler.
    $): You should place all relevant configuration files outside of both the upload directory and server root directory.
    $): You should prevent overwriting existing files which do not correspond to whitelisted patterns.
    $): You should generate upload names to strictly conform to the whitelisted patterns.

    You should also do most of the traditional unsafe validation. For reasons I do not understand, I don't see enough people using validation on the client and early MIME detection. Yes. The validation on the client and MIME detection can easily be faked. So? You still must use proper validation and limiting on the server, but the sooner you can catch a problem the better.

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  3. #3
    Unregistered User Yarin's Avatar
    Join Date
    Jul 2007
    Posts
    2,158
    Quote Originally Posted by MutantJohn View Post
    How do I make sure secure file uploads can be done with PHP?
    Over TLS, duh.


    Quote Originally Posted by MutantJohn View Post
    I've heard using any of the PHP $_FILE stuff is useless because the client can fake it all.
    I wouldn't say it's "faking" it, that data is simply whatever the client sent. And as you should know, never trust the client (this includes things in _POST and _GET).


    Quote Originally Posted by MutantJohn View Post
    Some of the tips I've seen are, move uploaded files to outside of the web root.
    Implementation detail.


    Quote Originally Posted by MutantJohn View Post
    I've also heard that you should use a randomly generate filename and serve the requested uploaded documents using a script file that I've defined.
    Doesn't matter. What do you want the file names to be.


    Quote Originally Posted by MutantJohn View Post
    Are these good tips?
    Good tips for what? What are you afraid of?


    Quote Originally Posted by MutantJohn View Post
    Is there anything I should be aware of?
    Make sure users can only upload files to places that the server has been configured to not execute.


    Quote Originally Posted by MutantJohn View Post
    I've heard that checking MIME types can be tricked and apparently, JPGs are like the most threatening thing in the entire world.
    JPGs are pictures. I guess an "attacker" could upload obscene pictures. That could be threatening, I guess.

  4. #4
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Quote Originally Posted by Yarin View Post
    Doesn't matter. What do you want the file names to be.
    Hmm, I do like the idea of just what looks to be gibberish. So long as my database is secure and the mapping works, I don't care. The more obscure the better.

    Good tips for what? What are you afraid of?
    Good tips for how to not be a nub lol. I'm so scared of just fudging everything up. I want potential users to know that when they use my site, there was some sort of effort and thought put into security. Granted, I do know that security itself could be its own full-time job.

    Make sure users can only upload files to places that the server has been configured to not execute.
    I was curious what you meant by this. Do you mean store all my uploads in the directories not listed in my apache2.conf under the Directory directives? The things that look like this?
    Code:
    <Directory /var/www/>
    	Options Indexes FollowSymLinks
    	AllowOverride All
    	Require all granted
    </Directory>
    JPGs are pictures. I guess an "attacker" could upload obscene pictures. That could be threatening, I guess.
    I had read stuff like this : Joseph Keeler » PHP Upload Security & The 1×1 jpeg Hack

    Thanks for the advice though, you guys! Very informative. phantom, I'll be sure I meet every one of those requirements.

    I may have totally dumped on how Ubuntu installed Apache in the past and I'm now ready to admit that not only was I super duper wrong, I was a super douche about it. I've now been humbled and have a better sense of appreciation because the default Ubuntu LAMP installation spreads the files out in a very intelligent manner.

  5. #5
    Unregistered User Yarin's Avatar
    Join Date
    Jul 2007
    Posts
    2,158
    Quote Originally Posted by MutantJohn View Post
    Good tips for how to not be a nub lol. I'm so scared of just fudging everything up.
    The rule of thumb is to just not trust data from the client any more than you have to. That's really it, follow that rule and you'll protect yourself from 99.9% of the hack vectors out there.


    Quote Originally Posted by MutantJohn View Post
    I was curious what you meant by this. Do you mean store all my uploads in the directories not listed in my apache2.conf under the Directory directives? The things that look like this?
    I mean, so that nothing in any of your upload directories are allowed to execute. So that, for example, if MyScript.php is uploaded then retrieved, it'll just send the file as-is, instead of the usual execution.

    Which, by the way, incidentally protects you from the JPEG attack you link to. I wasn't even aware of such attack, yet, my good practice would have protected me from it anyway.

  6. #6
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    I mean, so that nothing in any of your upload directories are allowed to execute. So that, for example, if MyScript.php is uploaded then retrieved, it'll just send the file as-is, instead of the usual execution.
    O_o

    A common setup for servers uses MIME handlers for processing scripts.

    The scripts don't have to be executable.

    The handler has to be executable.

    The script is only read by the handler.

    You could think in terms of typing commands into a shell.

    Code:
    ./test.php
    The test.php file needs the executable bit set because the shell will use `exec` or similar.

    Code:
    php ./test.php
    The test.php file does not need the executable bit set because the shell is only executing an interpreter.

    I wasn't even aware of such attack, yet, my good practice would have protected me from it anyway.
    Preventing execution of files inside an upload directory is only one step.

    You are still open to the same exploit if you are using some of the problematic configurations.

    You aren't even protected with good configurations if you use some of the common PHP techniques associated with building dynamic content because the interpreter only cares about read access in those situations.

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  7. #7
    Unregistered User Yarin's Avatar
    Join Date
    Jul 2007
    Posts
    2,158
    Quote Originally Posted by phantomotap View Post
    The scripts don't have to be executable.

    The handler has to be executable.

    The script is only read by the handler.

    You could think in terms of typing commands into a shell.

    Code:
    ./test.php
    The test.php file needs the executable bit set because the shell will use `exec` or similar.

    Code:
    php ./test.php
    The test.php file does not need the executable bit set because the shell is only executing an interpreter.
    Relying on the lack of an executable bit for security in this context sounds like a bad idea to me (but I guess so long as you have it under control, it's fine, each to their own).


    Quote Originally Posted by phantomotap View Post
    Preventing execution of files inside an upload directory is only one step.

    You are still open to the same exploit if you are using some of the problematic configurations.
    Lol. Guess what, you are open to a myriad of exploits if you have the a "problematic" configuration.


    Quote Originally Posted by phantomotap View Post
    You aren't even protected with good configurations if you use some of the common PHP techniques associated with building dynamic content because the interpreter only cares about read access in those situations.
    I don't know what you mean by "building dynamic content" as a "PHP technique", but it doesn't really matter, if you follow my #1 rule (don't trust client data), you won't be calling any user provided script from your own script in the first place; so again, no room for error. Even with clever JPEG hacks.

  8. #8
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    you won't be calling any user provided script from your own script in the first place
    O_o

    An image isn't a script.

    The exploit being discussed isn't you executing an uploaded script.

    You are not required to trust the payload as a script.

    You are not required to execute the payload as a script.

    The exploit being discussed is having servers execute code hidden within completely valid images by tricking the server into processing the payload using a handler associated with a specific interpreter which only requires read permissions.

    The thread is clearly intended to solicit advice as to how to resolve "don't trust client data" with allowing image uploads. You have never before now heard of such an exploit, and you don't know how the exploit works. You shouldn't even make claims that you know you are protected from exploits you don't understand. You certainly shouldn't pretend you know how to avoid exploits you don't understand.

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  9. #9
    Unregistered User Yarin's Avatar
    Join Date
    Jul 2007
    Posts
    2,158
    Quote Originally Posted by phantomotap View Post
    The exploit being discussed is having servers execute code hidden within completely valid images by tricking the server into processing the payload using a handler associated with a specific interpreter which only requires read permissions.

    The thread is clearly intended to solicit advice as to how to resolve "don't trust client data" with allowing image uploads. You have never before now heard of such an exploit, and you don't know how the exploit works. You shouldn't even make claims that you know you are protected from exploits you don't understand.
    Maybe it is you who doesn't understand how it works.
    Quote Originally Posted by http://josephkeeler.com/2009/04/php-upload-security-the-1x1-jpeg-hack/
    Name your file some_random_name.jpg.php
    See the extension? Yes? The exploit requires that the server is configured to allow execution of PHP from the upload area. Hence, if the server is configured to not do so, you are safe. End of story.

  10. #10
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    [Edit]
    ^_^

    I even know what's coming next from the playback.

    "Oh, I wasn't talking about that. You just misunderstood me."

    *sigh*

    I'm glad your back to more often posting.
    [/Edit]

    [Edit]
    I can't stand it; your post is too funny.

    Your post reads exactly like Elysia posting about a "GCC" bug after quoting the first page of a search result.
    [/Edit]

    Soma
    Last edited by phantomotap; 09-05-2015 at 11:33 AM.
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  11. #11
    Unregistered User Yarin's Avatar
    Join Date
    Jul 2007
    Posts
    2,158
    "Oh, I wasn't talking about that. You just misunderstood me."
    Are you trying to tell me something?


    You are not required to execute the payload as a script.
    You the server are, actually.
    Quote Originally Posted by http://josephkeeler.com/2009/04/php-upload-security-the-1x1-jpeg-hack/
    So Apache will process this file as a php file, and run it through the PHP interpreter prior to serving the file, executing the PHP code that was embedded in the jpeg header

  12. #12
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    You the server are, actually.
    O_o

    Oh Yarin, you are so much like Elysia I'm going to start calling you E2.

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  13. #13
    Unregistered User Yarin's Avatar
    Join Date
    Jul 2007
    Posts
    2,158
    I believe you already occupy that slot. Call me E3.

  14. #14
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    I believe you already occupy that slot. Call me E3.
    O_o

    What a silly thing to say, E2.

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  15. #15
    Unregistered User Yarin's Avatar
    Join Date
    Jul 2007
    Posts
    2,158
    You forgot the "=mc" part.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. HTTP File Upload Libcurl
    By binks in forum Networking/Device Communication
    Replies: 19
    Last Post: 07-21-2011, 06:16 PM
  2. file upload form in c++
    By Yarin in forum A Brief History of Cprogramming.com
    Replies: 1
    Last Post: 10-17-2008, 01:13 PM
  3. File Upload with libcurl
    By Tonto in forum Networking/Device Communication
    Replies: 4
    Last Post: 03-15-2006, 06:11 PM
  4. File security
    By fkheng in forum C Programming
    Replies: 13
    Last Post: 07-28-2003, 10:40 PM
  5. Anyone know a good file upload routine.
    By bjdea1 in forum C Programming
    Replies: 2
    Last Post: 12-08-2001, 12:04 PM