PHP data upload security and optimization [duplicate] - php

I am allowing users to upload files to my server. What possible security threats do I face and how can I eliminate them?
Let's say I am allowing users to upload images to my server either from their system or from net. Now to check even the size of these images I have to store them in my /tmp folder. Isn't it risky? How can I minimize the risk?
Also let's say I am using wget to download the images from the link that the users upload in my form. I first have to save those files in my server to check if they actually are images. Also what if a prankster gives me a URL and I end up downloading an entire website full of malware?

First of all, realize that uploading a file means that the user is giving you a lot of data in various formats, and that the user has full control over that data. That's even a concern for a normal form text field, file uploads are the same and a lot more. The first rule is: Don't trust any of it.
What you get from the user with a file upload:
the file data
a file name
a MIME type
These are the three main components of the file upload, and none of it is trustable.
Do not trust the MIME type in $_FILES['file']['type']. It's an entirely arbitrary, user supplied value.
Don't use the file name for anything important. It's an entirely arbitrary, user supplied value. You cannot trust the file extension or the name in general. Do not save the file to the server's hard disk using something like 'dir/' . $_FILES['file']['name']. If the name is '../../../passwd', you're overwriting files in other directories. Always generate a random name yourself to save the file as. If you want you can store the original file name in a database as meta data.
Never let anybody or anything access the file arbitrarily. For example, if an attacker uploads a malicious.php file to your server and you're storing it in the webroot directory of your site, a user can simply go to example.com/uploads/malicious.php to execute that file and run arbitrary PHP code on your server.
Never store arbitrary uploaded files anywhere publicly, always store them somewhere where only your application has access to them.
Only allow specific processes access to the files. If it's supposed to be an image file, only allow a script that reads images and resizes them to access the file directly. If this script has problems reading the file, it's probably not an image file, flag it and/or discard it. The same goes for other file types. If the file is supposed to be downloadable by other users, create a script that serves the file up for download and does nothing else with it.
If you don't know what file type you're dealing with, detect the MIME type of the file yourself and/or try to let a specific process open the file (e.g. let an image resize process try to resize the supposed image). Be careful here as well, if there's a vulnerability in that process, a maliciously crafted file may exploit it which may lead to security breaches (the most common example of such attacks is Adobe's PDF Reader).
To address your specific questions:
[T]o check even the size of these images I have to store them in my /tmp folder. Isn't it risky?
No. Just storing data in a file in a temp folder is not risky if you're not doing anything with that data. Data is just data, regardless of its contents. It's only risky if you're trying to execute the data or if a program is parsing the data which can be tricked into doing unexpected things by malicious data if the program contains parsing flaws.
Of course, having any sort of malicious data sitting around on the disk is more risky than having no malicious data anywhere. You never know who'll come along and do something with it. So you should validate any uploaded data and discard it as soon as possible if it doesn't pass validation.
What if a prankster gives me a url and I end up downloading an entire website full of malware?
It's up to you what exactly you download. One URL will result at most in one blob of data. If you are parsing that data and are downloading the content of more URLs based on that initial blob that's your problem. Don't do it. But even if you did, well, then you'd have a temp directory full of stuff. Again, this is not dangerous if you're not doing anything dangerous with that stuff.

1 simple scenario will be :
If you use a upload interface where there are no restrictions about the type of files allowed for upload then an attacker can upload a PHP or .NET file with malicious code that can lead to a server compromise.
refer:
http://www.acunetix.com/websitesecurity/upload-forms-threat.htm
Above link discusses the common issues
also refer:
http://php.net/manual/en/features.file-upload.php

Here are some of them:
When a file is uploaded to the server, PHP will set the variable $_FILES[‘uploadedfile’][‘type’] to the mime-type provided by the web browser the client is using. However, a file upload form validation cannot depend on this value only. A malicious user can easily upload files using a script or some other automated application that allows sending of HTTP POST requests, which allow him to send a fake mime-type.
It is almost impossible to compile a list that includes all possible extensions that an attacker can use. E.g. If the code is running in a hosted environment, usually such environments allow a large number of scripting languages, such as Perl, Python, Ruby etc, and the list can be endless.
A malicious user can easily bypass such check by uploading a file called “.htaccess”, which contains a line of code similar to the below: AddType application/x-httpd-php .jpg

There are common rules to avoid general issues with files upload:
Store uploaded files not under your website root folder - so users won't be able to rewrite your application files and directly access uploaded files (for example in /var/uploads while your app is in /var/www).
Store sanitated files names in database and physical files give name of file hash value (this also resolves issue of storing files duplicates - they'll have equal hashes).
To avoid issues with filesystem in case there are too many files in /var/uploads folder, consider to store files in folders tree like that:
file hash = 234wffqwdedqwdcs -> store it in /var/uploads/23/234wffqwdedqwdcs
common rule: /var/uploads/<first 2 hash letters>/<hash>
install nginx if you haven't done its already - it serves static like magic and its 'X-Accel-Redirect' header will allow you to serve files with permissions being checked first by custom script

Related

Are there risks of exploit with uploading a file this way?

I have a simple form in PHP that make the conversion of a file from XML to SQL or vice versa. In this form, there is an input where the user can upload a file with xml or sql extension. I do various check (extension of the file and file size), I read the file using the value tmp_name of the global array $_FILES, I do some operation for the conversion, and then I save the modified file in my server (compressed in gz) with the original name of the file in the client machine in order to give the link to the user and download it.
My question are: There are risks of exploit with the steps that I listed above? In general, there are risks of exploit with uploading a file? Or risks, to upload the file with the original name in the client machine?
Thanks.
There are always risks of exploit when allowing users to upload files, so it's good to be worried.
You say "I do some operation for the conversion", so while I cannot comment specifically on the safety of this operation, there could be risks here depending on the operation and the content provided to it (e.g. buffer overruns, invalid data).
I'm assuming you are saving your file with a .gz extension.
Saving with the client filename could pose compatibility problems if you do not clean the filename at all. There are differences in disallowed (or problem) characters between filesystems, such as & in Unix or : on Windows. Sometimes if you simply save a file, and simply read it again your code won't "find" it, unless you escape or strip all these characters properly.
The client filename could possibly pose a risk, if the name could have for example a path embedded into it. A presented filename such as "../../../../home/user/file" could possibly trick your program into overwriting a file, as long as the permissions were very badly implemented and you are simply concatenating paths. At worst I'd say this would be an annoyance or DoS attack - limited to overwriting gzip files and "breaking" them.
The client filename could possibly overwrite another user's files? I'm not sure what your namespacing is, but a clever attacker could try to trick another user into downloading their xml/sql file by naming it cleverly.
Also if you could guess someone else's filename, you could guess the resulting URLs and war-dial through them looking for content.
All of these risks would go away, if you used a nice GUID to name the file. Or mapped it to each user's session (e.g. file1.gz is only valid to that user's session).
I generally don't use client names, or seriously validate and clean them before re-presenting them.
The main risk of uploading files with php (and other interpreted languages, as a matter of fact) is that user can upload a .php file and if it's stored inside a web-root, then execute it.
From your question, it seems you only allow certain non .php extensions. Make sure you do this check on server-side, not just on the client. Also, if you don't need to serve the uploaded file on web afterwards, store it outside of your web-root. If you force the filename and extension after upload (not keeping the original one), then you can have even more control over what's going on in your part of the system.
Other file types can also be exploited (images for example, see https://imagetragick.com/) so it's a good idea to check specifically for the file-types you want uploadable.

PHP file renamed to JPG and uploaded to server a threat?

We have a server that has been compromised that is running WordPress and Magento and is running them on about 5 domains all on the same server.
The hacker has been uploading there malicious scripts through all the file-system in hundreds of locations. It is a nightmare at this stage and I am still unable to find the entry point.
I did just notice that one of our AJAX image upload fields allows me to rename a PHP file as a .jpg and upload the file to the server.
When I access the PHP .jpg file in the browser is serves a broken image.
So I am not sure if the hacker would be able to upload a PHP file here and access it as a PHP file or if it would just serve it as a broken image fore like it did for me in the browser?
Any ideas on how much of a security threat this could be? Could it potentially be my entry point where hacker gained initial access? Or is the fact it serves as a broken image instead of processing the PHP file when I load in my browser mean that its somewhat secure?
Any help appreciated, thank you
Hard to say if the hacker has done something without actually checking what's there.
Regarding how to secure future image uploads I would advice using a function like finfo in PHP http://php.net/manual/en/function.finfo-file.php to find if a file belongs to any of the approved mime types, which btw, you should restrict to only a limited type of image types.
Also you should consider not allowing the use of the original image, but instead an adjusted version of it, to avoid that users end up downloading huge images or things like that.
Answer:
Usually (depending on the web server configuration) no one can execute a PHP file if it has a different extension, they could have upload it, but they can't run it, at least in any common configuration.
So, in theory you should not have to worry for that specific thing, but do be worry that someone is spending time in trying to hack you and that means you should expend time protecting the site and server.
I would recommend searching for articles on how to protect your specific server and configuration and to make sure you update your software, OS and such to the latest security updates.
Being able to upload a file with .jpeg file extension but PHP content is not a vulnerability in itself. However:
if the attacker is writing all over the file system you might have an upload function with a directory traversal vulnerability which will need fixing, ideally by not letting the uploader choose their own filename at all;
there are other problems to do with cross-site-scripting when you let users upload content to be served from the same hostname as the site;
it may be worth checking an uploaded file using something like getimagesize() to ensure that you have a JPEG file and non-ridiculous dimensions, but given the possibility of ‘chameleon’ files that can be interpreted as multiple different types this is not necessarily watertight, so this is a ‘defense-in-depth’ measure at best.
Getting a web server to run a .jpeg file as PHP code could happen by:
being able to write to server configuration to associate .jpeg with the PHP handler. Typically this would happen because another vulnerable file upload feature allowed an attacker to write a .htaccess file in the same directory for Apache to pick up.
a PHP script with a Local File Inclusion security hole. Typically this would be code like:
include("include/$variable");
where an attacker can get content into $variable, to point to something.jpeg. Generally include/require should never be used with variables unless those variables are explicitly limited to a few known-good values.
The other likely possibility if you have a load of malicious pages uploaded to your server is that your server login is compromised.

Securing Uploaded Files (php and html)

I have a simple site which allows users to upload files (among other things obviously). I am teaching myself php/html as I go along.
Currently the site has the following traits:
--When users register a folder is created in their name.
--All files the user uploads are placed in that folder (with a time stamp added to the name to avoid any issues with duplicates).
--When a file is uploaded information about it is stored in an SQL database.
simple stuff.
So, now my question is what steps do I need to take to:
Prevent google from archiving the uploaded files.
Prevent users from accessing the uploaded files unless they are logged in.
Prevent users from uploading malicious files.
Notes:
I would assume that B, would automatically achieve A. I can restrict users to only uploading files with .doc and .docx extensions. Would this be enough to save against C? I would assume not.
There is a number of things you want to do, and your question is quite broad.
For the Google indexing, you can work with the /robots.txt. You did not specify if you also want to apply ACL (Access Control List) to the files, so that might or might not be enough. Serving the files through a script might work, but you have to be very careful not to use include, require or similar things that might be tricked into executing code. You instead want to open the file, read it and serve it through File operations primitives.
Read about "path traversal". You want to avoid that, both in upload and in download (if you serve the file somehow).
The definition of "malicious files" is quite broad. Malicious for who? You could run an antivirus on the uplaod, for instance, if you are worried about your side being used to distribute malwares (you should). If you want to make sure that people can't harm the server, you have at the very least make sure they can only upload a bunch of filetypes. Checking extensions and mimetype is a beginning, but don't trust that (you can embed code in png and it's valid if it's included via include()).
Then there is the problem of XSS, if users can upload HTML contents or stuff that gets interpreted as such. Make sure to serve a content-disposition header and a non-html content type.
That's a start, but as you said there is much more.
Your biggest threat is going to be if a person manages to upload a file with a .php extension (or some other extension that results in server side scripting/processing). Any code in the file runs on your server with whatever permissions the web server has (varies by configuration).
If the end result of the uploads is just that you want to be able to serve the files as downloads (rather than let someone view them directly in the browser), you'd be well off to store the downloads in a non web-accessible directory, and serve the files via a script that forces a download and doesn't attempt to execute anything regardless of the extension (see http://php.net/header).
This also makes it much easier to facilitate only allowing downloads if a person is logged in, whereas before, you would need some .htaccess magic to achieve this.
You should not upload to webserver-serving directories if you do not want the files to be available.
I suggest you use X-Sendfile, which is a header that instructs the server to send a file to the user. Your PHP script called 'fetch so-and-so file' would do whatever authentication you have in place (I assume you have something already) and then return the header. So long as the web server can access the file, it will then serve the file.
See this question: Using X-Sendfile with Apache/PHP

Security risk if allowing all file type extensions on user uploads

Background: I have a website where people can store transactions. As part of this transaction, they could attached a receipt if they wanted.
Question: Is there any security risk if a user is allowed to upload any type of file extension to my website?
Info:
The user will be only person to ever re-download the same file
There will be no opportunity for the user to "run" the file
They will only be able to download it back to themselves.
No other user will ever have access to another users files
There will be a size restriction on the say (say 2mb)
More info: I was originally going to restrict the files to "pdf/doc/docx" - but then realised some people might want to store a jpg, or a .xls etc - and realised the list of files they "might" want to store is quite large...
edit: The file will be stored outside public_html - and served via a "readfile()" function that accepts a filename (not a path) - so is there anything that can 'upset' readfile()?
Yes, it is definitely a security risk unless you take precautions. Lets say, to re-download the file, the use has to go to example.com/uploads/{filename}. The user could upload a malicious PHP file, and then 'redownload' it by going to example.com/uploads/malicious.php. This would, of course, cause the PHP script to execute on your server giving him enough power to completely wreck everything.
To prevent this, create a page that receives the filename as a parameter, and then serve the page to the user with the correct content-type.
Something like, example.com/files?filename=malicious.php
"There will be no opportunity for the user to "run" the file"
As long as you are 100% sure that that will hold true, it is secure. However, make sure the file will not be able to be executed by the webserver. For example, if the user uploads a .php file, make sure the server does not execute it.
Computers don't run programs magically by themselves, so basically you just need to ensure that the user has no ability to trick your server into running the file. This means making sure the proper handlers are disabled if the files are under the web root, or passing them through a proxy script if they are not (basically echo file_get_contents('/path/to/upload') with some other logic)
Another option would be to store the file like name.upload but this would require keeping a list of original names that map to the storage names.

Securing files in PHP site

I've got a site that accepts user-uploaded files (images, pdfs, word docs, etc.) then allows other users to download them.
I realize this presents a security risk, since malicious users could upload scripts etc. that masquerade as useful files.
My question is this-- is it enough to check the mime type of the file being uploaded using PHP (mime_content_type or finfo) and set the file to read only (non-executable), or must I also store the uploaded files in a directory that is outside the web root? I would think this would eliminate most of the risk from the uploaded file, but I'm not sure. Performing a virus scan on uploaded files is not possible in this situation.
Thanks for input.
A common practice is to upload files outside the document root, and typically using randomized filenames which are then mapped to the correct item/object/post in the database. If additional permissions are needed to access the files, make sure you check them before allowing downloads, and of course you'll have only authenticated users uploading.
Fileinfo finfo_ is useful for validating most mimetypes, at least to verify that something called ".txt" is actually a text file and not a binary blob, or that a ".jpg" really appears to be a jpeg based on its first few or last few bytes. It may require some extra work sorting out MS Office mimetypes, as if I recall correctly, they all come out as application-msword. But you can then use the file extension to figure out what it is really supposed to be (xls, ppt, doc, etc).
A PHP script then supplies the downloaded file, rather than the web server directly serving it. For that reason, you should store the mime type along with it, so that you can serve the appropriate headers.
header("Content-type: application-whatever");
header("Content-length: size-of-the-file-in-bytes");
I can recommend you use every tool at your disposal to test for the file type. But know that there are other ways a hacker can implant a dangerous file.
Your best bet is to have the files be uploaded to a different server. One that can only host files.
I would check the mime type of the file but I wouldn't rely on this. Even if the file is a full blown .gif and contains a comment in its id3 tag which is a php, it can be executed with a local file include. A safer approach would be store files in the database using a long blob datatype. However this kind of overhead is crap.
The best solution from the perspective of security, scalability and perforce would be to use a no-sql database like CouchDB.
A few things to keep in mind, don't trust $_FILES[]. $_FILES['type'] could be anything the attacker wants so there is no point in checking it from a security perspective. And $_FILES['name'] could have nasty input like ../../../. Its best to rename files to the primary key and then store information about that file in a relational database (like mysql).

Categories