Suppose that our web-hosting is linux and php is installed:
1- What could be the worst that happens when a php code can be uploaded instead of an image.
2- Can the intruder somehow retrieve my database password ? suppose that the directory on which images get stored has 777 file permissions.
3- What if when the image directory has 644 permission?
The answer to my question can be combined with the ones given to these two: Security: How to validate image file uploads? and Security issues in accepting image uploads
What could be the worst that happens when a php code can be uploaded instead of an image.
Worst case: Intruder can execute arbitrary PHP code, maybe even arbitrary code on the server. If the attacker is clever enough while the sysadmins aren't, he might even own the whole server/subnet/network/...
Can the intruder somehow retrieve my database password ? suppose that the directory on which images get stored has 777 file permissions.
If the attacker can execute PHP code (which of course depends on your security measures), he can definitely read files from the current user, so the answer is most probably yes.
What if when the image directory has 644 permission?
Unless you use PHP in CGI mode, the execute bit shouldn't be necessary for the webserver to execute a script, so that alone doesn't help.
Of course those are not the questions you should ask. The question you should ask is how to prevent an attacker from uploading an executable PHP file in the first place. My answer to that is that you should check the file extension against a white list and drop everything else, for example:
$pattern = "/\.(jpe?g|gif|png)$/iD";
if (!preg_match($pattern, $filename))
die("Please don't.");
You should make sure you don't allow parsing of php files in your image directory, since I'm assuming it's going to be open to the public.
You could do this in the /images/.htaccess file with
RemoveHandler .php .phtml .php3
RemoveType .php .phtml .php3
That way if they try to go to domain.com/images/hackdatabase.php it'll just return their code and not the file.
But you should check to make sure its' an image in the first place.
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'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
I've created (using a script and some help from Stack and some help from friends; I know very little about PHP) a simple page for a local non-profit publication where people can upload photos.
I'm not great with security (from a basis of ignorance, not deliberate negligence) but I've taken the following steps to protect this page:
• the PHP script is set to only accept .jpg, .png and .tif files for upload;
• the subfolder that it saves the form content to has permissions set at 700, and the subfolder it saves uploaded photos to has permissions set at 700;
• according to documentation, my host has the following configuration to ensure that only .php files run as .php:
<FilesMatch \.php$>
SetHandler php52-fcgi
</FilesMatch>
• I’ve put an .htaccess file in the relevant (main and saved content) folders:
RemoveHandler .php
RemoveHandler .inc
RemoveHandler .pl
RemoveHandler .cgi
RemoveHandler .py
RemoveHandler .fcgi
Overnight, however, somebody found this test page and submitted what seems to be a perfectly benign test message and small .jpg. This is a private test page with a non-intuitive URL that only I and about three other people know about; none of the others sent this test.
This obviously has me worried that there's something hinky going on, and I'm worried that I don't know enough about security to make sure this page is safe.
Is there something obvious that I'm missing?
When dealing with uploaded you should keep in mind that all the data you can find in the $_FILES array can be faked. It's traveling through HTTP so it's pretty easy to give the image/jpg mime to an executable file for exemple.
1- Check the true mime
PHP come with some function to check the real mime of a file. For that you should use fileinfo
$finfo = new finfo(FILEINFO_MIME, "/usr/share/misc/magic");
$filename = "/var/tmp/afile.jpg";
echo $finfo->file($filename);
2- Check the image's properties
You apparently want to upload only image , so the received file must have a width and a height :
Use getImageSize() to get all the required information about the image. If it return false , the file is probably not an image and you can delete it.
getImageSize can also give you a mime type , but i don't know if it can be trusted.
2.5- Reprocess image
As suggested by user628405 , reprocessing the image with GD is probably the more secure thing to do.
$img = imagecreatefrompng('vulnerable.png');
imagepng($img, 'safe.png');
Obviously it has to be adapted according to the image type. See all the imagecreatefrom* in php documentation.
3- Upload folder
In addition of what you have already done :
Make sure your upload folder is not available from the web. Validate the uploaded file then move it to an other folder if needed and rename the file.
It will prevent hacker from executing a malicious file (can't execute it if it can't be reached by an url).
Further reading : https://www.owasp.org/index.php/Unrestricted_File_Upload
Don't rely on any data from the client, including content type!
Don't save uploaded files in the web root. Uploaded files should be only accessible via your scripts, for better control.
Don't save uploaded files with their original file names and extensions! Store this data in a database for retrieval later.
You can check the MIME type of the file, but don't worry as long as your php handler can only execute .php files and you're taking care of not saving uploaded .php files in your script, you're not exposing any security leak.
This is valid for .php files as well as any other server-side scripting language installed on your server of course.
A better idea is to keep a white of the extensions you're accepting to save on your filesystem.
I would ignore the MIME type and the file extension of the incoming file. These can be faked.
Store those files in a directory if you are going down that avenue.
Ensure that that directory is just for images (music) and then get a script to place the correct extension on them by looking at the files format.
Also ensure that that directory cannot execute PHP (or anything else).
This will keep you safe.
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
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.