PHP - Why use move_uploaded_file and not rename? - php

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.

Related

What is the risk in file upload forms if I rename the file and move it somewhere else

I'm reading about security stuff for PHP and my biggest concern now is the users file upload form. I've read a lot that some users may upload files that seems to be something else by changing the extension or even manipulating the header and the mimetype. I understand this.
But my question is how will this be an issue if I rename any uploaded file and move it to a directory that they do not know.
Please let me know if this will be enough or not, and if not, just give me some headline of what extra security checks should I perform
Thanks a lot
It really depends on what your online application is looking to achieve. If you wish to limit access directly to files which are uploaded, then you should set the folder permissions for the parent folder of the uploaded area to block user access. Then in your database you can record to path and only host the files through the http response. This will ensure that no files are accessed which could be potentially harmful, and also that users can still upload what they feel. As an extra step, you could add an erroneous file extension to each file while it is hosted and then remove it when it is served.
You might run an antivirus scan daemon in the background like avscand, configured. for scanning and moving infected files to a quarantaine directory. This ought to prevent delivering infected files later back to the people. Configure automatic virus database updating. A bit back that I did do such things, so investigate.
A simple renaming of the file name to one with safe characters should be sufficient; per user separated of course.
To have a more secure site the following needs to happen:
Due to the nature of security, this list will need be updated every so often.
Set the upload_max_filesize to something sensible
Install an Antivirus on the server
Set the upload_tmp_dir to something sensible, that the user may not access. See Setting PHP tmp dir - PHP upload not working
Have your form you upload files (which you already have done)
Your form handler should:
Run a file command to get the type of the data without executing it
Reject random files
The PHP interpreter will validate the file size
Run the virus scanner on the file
Do a file rename to ensure the filename is clean (if you need to reference things, it is convenient to rename the file to the primary key of your attachments table)
Move the file to a location that isn't accessible by the client (but move it, so if a later upload comes in with the same name nothing happens)
When you move the files, ensure they don't have execute permissions

Security in uploading any file types to server in php [duplicate]

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

Safe image upload in PHP [duplicate]

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

Dangerous file types to avoid in file-sharing website

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).

Stop people uploading malicious PHP files via forms

I have an upload form created in php on my website where people are able to upload a zip file. The zip file is then extracted and all file locations are added to a database. The upload form is for people to upload pictures only, obviously, with the files being inside the zip folder I cant check what files are being uploaded until the file has been extracted. I need a piece of code which will delete all the files which aren't image formats (.png, .jpeg, etc). I'm really worried about people being able to upload malicious php files, big security risk! I also need to be aware of people changing the extensions of php files trying to get around this security feature.
This is the original script I used http://net.tutsplus.com/videos/screencasts/how-to-open-zip-files-with-php/
This is the code which actually extracts the .zip file:
function openZip($file_to_open) {
global $target;
$zip = new ZipArchive();
$x = $zip->open($file_to_open);
if($x === true) {
$zip->extractTo($target);
$zip->close();
unlink($file_to_open);
} else {
die("There was a problem. Please try again!");
}
}
Thanks, Ben.
Im really worried about people being able to upload malicious php files, big security risk!
Tip of the iceberg!
i also need to be aware of people changing the extensions of php files trying to get around this security feature.
Generally changing the extensions will stop PHP from interpreting those files as scripts. But that's not the only problem. There are more things than ‘...php’ that can damage the server-side; ‘.htaccess’ and files with the X bit set are the obvious ones, but by no means all you have to worry about. Even ignoring the server-side stuff, there's a huge client-side problem.
For example if someone can upload an ‘.html’ file, they can include a <script> tag in it that hijacks a third-party user's session, and deletes all their uploaded files or changes their password or something. This is a classic cross-site-scripting (XSS) attack.
Plus, thanks to the ‘content-sniffing’ behaviours of some browsers (primarily IE), a file that is uploaded as ‘.gif’ can actually contain malicious HTML such as this. If IE sees telltales like (but not limited to) ‘<html>’ near the start of the file it can ignore the served ‘Content-Type’ and display as HTML, resulting in XSS.
Plus, it's possible to craft a file that is both a valid image your image parser will accept, and contains embedded HTML. There are various possible outcomes depending on the exact version of the user's browser and the exact format of the image file (JPEGs in particular have a very variable set of possible header formats). There are mitigations coming in IE8, but that's no use for now, and you have to wonder why they can't simply stop doing content-sniffing, you idiots MS instead of burdening us with shonky non-standard extensions to HTTP headers that should have Just Worked in the first place.
I'm falling into a rant again. I'll stop. Tactics for serving user-supplied images securely:
1: Never store a file on your server's filesystem using a filename taken from user input. This prevents bugs as well as attacks: different filesystems have different rules about what characters are allowable where in a filename, and it's much more difficult than you might think to ‘sanitise’ filenames.
Even if you took something very restrictive like “only ASCII letters”, you still have to worry about too-long, too-short, and reserved names: try to save a file with as innocuous a name as “com.txt” on a Windows server and watch your app go down. Think you know all the weird foibles of path names of every filesystem on which your app might run? Confident?
Instead, store file details (such as name and media-type) in the database, and use the primary key as a name in your filestore (eg. “74293.dat”). You then need a way to serve them with different apparent filenames, such as a downloader script spitting the file out, a downloader script doing a web server internal redirect, or URL rewriting.
2: Be very, very careful using ZipArchive. There have been traversal vulnerabilities in extractTo of the same sort that have affected most naive path-based ZIP extractors. In addition, you lay yourself open to attack from ZIP bombs. Best to avoid any danger of bad filenames, by stepping through each file entry in the archive (eg. using zip_read/zip_entry_*) and checking its details before manually unpacking its stream to a file with known-good name and mode flags, that you generated without the archive's help. Ignore the folder paths inside the ZIP.
3: If you can load an image file and save it back out again, especially if you process it in some way in between (such as to resize/thumbnail it, or add a watermark) you can be reasonably certain that the results will be clean. Theoretically it might be possible to make an image that targeted a particular image compressor, so that when it was compressed the results would also look like HTML, but that seems like a very difficult attack to me.
4: If you can get away with serving all your images as downloads (ie. using ‘Content-Disposition: attachment’ in a downloader script), you're probably safe. But that might be too much of an inconvenience for users. This can work in tandem with (3), though, serving smaller, processed images inline and having the original higher-quality images available as a download only.
5: If you must serve unaltered images inline, you can remove the cross-site-scripting risk by serving them from a different domain. For example use ‘images.example.com’ for untrusted images and ‘www.example.com’ for the main site that holds all the logic. Make sure that cookies are limited to only the correct virtual host, and that the virtual hosts are set up so they cannot respond on anything but their proper names (see also: DNS rebinding attacks). This is what many webmail services do.
In summary, user-submitted media content is a problem.
In summary of the summary, AAAARRRRRRRGGGGHHH.
ETA re comment:
at the top you mentioned about 'files with the X bit set', what do you mean by that?
I can't speak for ZipArchive.extractTo() as I haven't tested it, but many extractors, when asked to dump files out of an archive, will recreate [some of] the Unix file mode flags associated with each file (if the archive was created on a Unix and so actually has mode flags). This can cause you permissions problems if, say, owner read permission is missing. But it can also be a security problem if your server is CGI-enabled: an X bit can allow the file to be interpreted as a script and passed to any script interpreter listed in the hashbang on the first line.
i thought .htaccess had to be in the main root directory, is this not the case?
Depends how Apache is set up, in particular the AllowOverride directive. It is common for general-purpose hosts to AllowOverride on any directory.
what would happen if someone still uploaded a file like ../var/www/wr_dir/evil.php?
I would expect the leading ‘..’ would be discarded, that's what other tools that have suffered the same vulnerability have done.
But I still wouldn't trust extractTo() against hostile input, there are too many weird little filename/directory-tree things that can go wrong — especially if you're expecting ever to run on Windows servers. zip_read() gives you much greater control over the dearchiving process, and hence the attacker much less.
First you should forbid every file that doesn’t have a proper image file extension. And after that, you could use the getimagesize function to check whether the files are regular image files.
But furthermore you should be aware that some image formats allow comments and other meta information. This could be used for malicious code such as JavaScript that some browsers will execute under certain circumstances (see Risky MIME sniffing in Internet Explorer).
You should probably not rely just on the filename extension, then. Try passing each file through an image library to validate that its really an image, also.
I don't see the risk in having renamed php files in your DB...
As long as you're not evaluating them as PHP files (or at all, for that matter), they can't do too much harm, and since there's no .php extension the php engine won't touch them.
I guess you could also search the files for <?php...
Also: assume the worst about the files uploaded to your machine. Renamed the folder into which you're saving them "viruses" and treat it accordingly. Don't make it public, don't give any file launch permissions (especially the php user), etc.
You might also want to consider doing mime type detection with the following library:
http://ca.php.net/manual/en/ref.fileinfo.php
Now you are relying on your harddrive space for extracting. You can check fileheaders to determine what kind of files they are. there probably libraries for that.
offtopic: isnt it better to let the user select couple of images instead of uploading a zip file. Better for people that don't know what zip is (yes they exist)
If you set php to only parse files ending with .php, then you can just rename a file from somename.php to somename.php.jpeg and you are safe.
If you really want to delete the files, there is a zip library available to php. You could use it to check the names and extensions of all the files inside the zip archive uploaded, and if it contains a php file, give the user an error message.
Personally, I'd add something to the Apache config to make sure that it served PHP files as text from the location the files are uploaded to, so you're safe, and can allow other file types to be uploaded in the future.
Beaware of this Passing Malicious PHP Through getimagesize()
inject PHP through image functions that attempt to insure that images
are safe by using the getimagesize() function
read more here http://ha.ckers.org/blog/20070604/passing-malicious-php-through-getimagesize/
Better for your user logo use gravatar like here used by Stackoverflow ;)
Use getimagesize function.
Full procedure:-
1.) Extract extension of image/uploaded file and then compare extension with allowed extension.
2.) Now create a random string for renaming uploaded file. best idea is md5(session_id().microtime()).It can not be duplicated and if your server is very fast and can process less than a microsecond than use incremented variable and add them with string.
now move that file.
A tip
Disable PHP file processing in upload directory, it will always prevent you from any server side attack and if possible add your htaccess in root directory or in httpd config file and disable htaccess files from there now it solve your maximum problems

Categories