I am making a feature to my site so that users can upload files (any type).
In order to secure the upload form, i made a blacklist of non-accepted filetypes. But in order to assure protection to my server (in case of uploading malicious scripts in any way) i thought to tar the uploaded files (using the tar class) so that they are stored as .tar zipped files.
So if the user wants to donwload it, then he will receive a .tar file.
My question is, is this secure enough? (since the files cannot be executed then).
[I have this reservation as i can see at the code of tar class, the "fread()"]
Thanks!
Two points, here :
Using a blacklist is a bad idea : you will never think to all possible evil filetypes.
Do not store the uploaded files into a public directory of your server :
Store those files to a directory that is not served by Apache, outside of your DocumentRoot.
And use a PHP script (even if Apaches cannot serve the files through HTTP, PHP can read them) to send those files contents to the user who wants to download them.
This will make sure that those uploaded files are never executed.
Of course, make sure your PHP script that sends the content of a file doesn't allow anyone to download any possible file that's on the server...
You can upload the files to an non web accessible location (under your webroot) and then use a download script to download the file.
The best way of handling uploaded files, in my opinion, is to place them in a folder that's not reachable through HTTP. Then when a file is requested, use a PHP file to send then download headers, the use readfile() to send the file to the user. This way, files are never executed.
That might work, assuming that you're users that will download the files can untar them (most non UNIX systems just have zip, I'd give them the option to download either format).
Also, i think its better to create a list of allowed files vs banned files. Its easy to forget to ban a specific type; whereas you will probably have a better idea of what users can upload
Dont block/allow files on extension. Make sure you are using the mime type that the server identifies the file as. This way its hard for them to fake it.
also, store the files in a non web accessible directory and download them through a script.
Even if its a bad file, they won't be able to exploit it if they can't directly access it .
When saving the files make sure you use these functions:
http://php.net/manual/en/function.is-uploaded-file.php
http://php.net/manual/en/function.move-uploaded-file.php
Dan
Related
In the manual I can see it says something about security reasons, but I didn't quite understand what is the problematic situation.
This function checks to ensure that the file designated by filename is
a valid upload file (meaning that it was uploaded via PHP's HTTP POST
upload mechanism). If the file is valid, it will be moved to the
filename given by destination.
This sort of check is especially important if there is any chance that
anything done with uploaded files could reveal their contents to the
user, or even to other users on the same system.
So it makes sure it was uploaded via PHP, but if it will not check that, what could happen? what information could be revealed, and how?
Can someone explain this? An example will be great.
A PHP script will likely move files around whose name is determined at runtime (the name of a temporary file that has just been uploaded). The check is meant to ensure that poorly-written scripts don't expose system files, or files containing authentication secrets.
Suppose I write a script that lets you upload an image to my server, enhance it by embedding some super-cute cat gifs that I provide, and download it again. To keep track of which image you are working on, I embed the file name in the request URLs for my edit buttons:
http://example.com/add-kitty.php?img=ato3508.png&add=kitty31.gif
Or maybe I embed the same information in a cookie or POST data, wrongly thinking that this makes it more secure. Then some moderately enterprising script kiddie comes by and tries this (or the POST/cookie equivalent):
http://example.com/add-kitty.php?img=$2Fetc%2Fpasswd&add=kitty31.gif
See it? That's the path /etc/passwd, url-encoded. Oops! You may have just made your /etc/passwd file available for download, with a little kitty noise in the middle.
Obviously this is not a full working exploit for anything, but I trust you get the idea: The move_uploaded_file function makes the extra check to protect you from attacks that will inject an unintended filename into your code.
The security issue in this case is the upload directory will be visible to public.
To avoid this case, you need to configure your web server such as Apache to make the directory forbidden to public.
Also, whenever you upload file through PHP script, rename files with mixed characters.
For example, you could use encrypted timestamps combined with actual file name.
It seems to be conventional to handle file uploads. You could stick with this way to handle file uploads securely.
EDITED:
This answer is edited as per your question in the comment.
You need to have an existing file within any of your www directory to rename it with rename($existing_old_file_name, $new_file_name) function.
move_uploaded_file($tmp_uploaded_file_name, $new_file_name) function moves the uploaded file from the tmp directory to the destination you specify as a second parameter in the function.
I've tried to look around for some tricks on how I can do this safely, without executing the code.
Does the code get executed if i simply upload it to the file system, then leave it be until someone downloads it?
Or is this a potential threat aswell?
What I am trying to do is making the users able to upload their CV in pdf files. The administrator can then download this pdf file (not being viewed on server, but downloaded).
How should I do this to prevent malicious files from being executed on my server? Also, would it be risky to place this folder OUTSIDE the public_html folder?
There's not a lot of risk to upload .pdf in a folder.
the folder must be in 644 (chmod). and have a index.php with redirect to the index of the website
Inside or outsite the "public_html" .. it's not a problem
when you upload, you can check the extension (.pdf) and type mime:
with finfo_file (http://php.net/manual/en/function.finfo-file.php )
and
with $extension = substr($file, -3);
That depends on how your server is set. If it allows PDF files to be used as executable, or to be opened with particular application/processing script that could be used for malicious actions. Otherwise you have to follow simple instructions such as restriction of file name length and avoiding to perform read operation of that file. As I understand you need only to upload and safe them. I'd keep them in public_html and once uploaded correctly (you checked filesize, extension etc) moved them whenever you like.
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
I am making a small file-sharing website where users can upload content. Recently somebody uploaded a PHP script that was presumably intended to harm the site. It got me thinking: what file types should I block users from uploading? I have already blocked .exe files. What other file types could cause harm to either my website or its users?
This script can be viewed here.
Don't store the files where they're directly accessible - only provide access via a script YOU control. Don't store the files using their user-supplied filename - use a filename YOU generate (best option is to store file details in a database, including the original filename, and store the actual file using that db record's primary key field.
With those two, people can upload antyhing they want, and there'll be zero chance of the file being executed/interpreted on your server, because it's never in a position where it CAN be executed/interpreted.
It looks like the script is cut off while it's still defining functions, so I can't make out what it's doing.
However, if you're doing things correctly you should have an .htaccess file in your "uploaded files" directory with:
Header set Content-Disposition "attachment"
This will ensure that accessing any file in that directory will result in a download, and that script will not be run.
(Actually even better is to have the files outside the webroot, and have a "downloader" php script echoing the file contents)
That script could euphemistically be described as a remote administration script.
You should always use a whitelist, not a blacklist. Instead of "enumerating badness", make a list of allowed file types and reject everything else.
Also, all files uploaded should be put in a directory which does not run the PHP handler, or any other script handlers at all (check for instance what other content management systems written in PHP do in the .htaccess for their upload directories).
It is also a good idea to put the uploaded files in a separate subdomain which does not have any access to the cookies of the main domain, to avoid attacks which attempt to run JavaScript code on the same origin as the main site (a whitelist of content types is not enough for this, since some browsers are known to guess the content type and treat non-HTML files as HTML).
I have read the following tutorial "Uploading Files To the Server Using PHP"
and have several questions related to the topics.
Q1> The tutorial mentions that
"Note that PHP must have write access
to $uploadDir or else the upload will
fail"
For me, I only allow the user to upload the file after the user has login to the website.
If we set that $uploadDir permission as 777, then everyone can have written permission to that folder. How to avoid this problems?
Also I am using WAMP as my testing bed, can I simulate the same case as a real web server?
Q2> In order to prevent Preventing direct access, the tutorial mentions:
"A better approach is to move the
upload directory away from your web
root. For example, the web root for
this site is:
/home/arman198/public_html/ to prevent
direct listing i can set the upload
directory to /home/arman198/upload/."
Now my problem is that how can I display the uploaded images on other website pages. Since, the upload is not accessible directly anymore? I need to display the uploaded image save personal headshot dynamically on other website page. Is it possible?
Thank you
It's a common problem.
All modern computers have a temporary files directory. On Linux/Unix it's /tmp, on Windows it's usually c:\temp. The OS install will have set permissions on that directory so that anyone can write files there but only privileged users can delete files that don't belong to them. This is where PHP will want to put an uploaded file; your application then has to move it elsewhere (this is the purpose of the move_uploaded_file() function). PHP under Windows may need upload_tmp_dir actually set in the php.ini file.
Once you have an uploaded file, you can shift it whereever you like, including to where the webserver can read it to serve it. The biggest problem with that it is awfully easy to put this directory inside your codebase. Don't do that. As soon as you do anything beyond editing the files inside the directory they are served from, it will be problematic. Trust me: I've dealt with a few times this in code I've inherited. It's easy to let your webserver load files from a location outside your codebase.
The other alternative is to produce a download script. That way the file need not be servable by the webserver at all. One disadvantage is that you don't get to leverage the web server's MIME translation, but then, that lets you control which types of image files are permitted.
For the second question, you can use a PHP script intead of direct access to the directory. Lets name it image.php. Lets assume that it can take a parameter id, like image.php?id=image_id. In that file you can get the id using superglobal array $_GET. Then you can search for images with that Id and just send it as response.
First one I'm not sure, but maybe play with .htaccess file.
And for the first question, try setting your permissions to 775. That should allow PHP to write the file to the directory without giving the general public write access.