PHP File upload, Secure? - php

This is what I want an user to be able:
Upload ANY file to the server (attachment) to the uploads folder
Be Able to download it afterwards
So I have created this dir with the following .htaccess
Allow from all
DirectoryIndex .x
php_flag engine off
Options -Indexes
Options -ExecCGI
AddType text/plain .html .htm .shtml .php .php3 .php5 .phtml .phtm .pl .py .cgi
ForceType applicaton/octet-stream
My question is, is this secure?

I would like to say: no
It should be more secure if you deny access from all and manage the download via a script that deliveres the files.
Furthermore you should rename the files, so that there e.g. nobody places his own htaccess or whatever.
The original filenames you can store in a DB.
Why: You will never know what happens in the future, some files can later get executable, somewhere else you place an insecure script that allows users to include those uploaded files, and so on.

I also agree with Dr.Molle that you should rename the files and send them dynamically.
But instead of sending them via a script, which will take up much more memory than necessary, I highly recommend using mod_xsendfile for Apache.
With mod_xsendfile, instead of outputting the file through PHP, you can simply send the XSendFile headers:
<?php
header('Content-Disposition: attachment;filename=originalname.txt');
header('X-Sendfile: /path/to/file.txt');
?>
This way, you can keep all the files OUTSIDE the web directory root and therefore completely inaccessible to the outside world. You won't have to worry about .htaccess at all.
If your host allows you to install new Apache modules, you'll need apxs installed (it probably will be). If it's not installed, you'll need to rebuild Apache with apxs enabled. In my experience, if you can manage it, it's worth it. XSendFile saves SO much trouble.

I agree that it would be much better to download them via special script. But if it's not possible, do two things:
If you wish users to be able to download files, you can add attachment HTTP response header
Header set Content-disposition "attachment"
which will force browser to download file instead of rendering it.
Still, you have to make sure files won't be accessible through other potential vulnerabilities like File Inclusion.
Forbid execution for upload directory with chmod -R a-x

Related

PHP file executing despite using 'ForceType image/jpeg' in .htaccess

To prevent any PHP files from executing if uploaded to my image directory, I have created a .htaccess file solely containing ForceType image/jpeg, placed within this directory.
While this successfully causes evil.txt to be interpreted as an image file when opened by a browser, evil.php executes just fine (it echoes text to the browser). I have even tried directly targeting it:
<FilesMatch "evil.php">
ForceType image/jpeg
</FilesMatch>
But this doesn't work either.
Those are two completely unrelated things. ForceType is for the client, not the web server. The thing that's interpreting the PHP is your apache httpd web server. The way it knows to interpret a file as PHP or not is based on your FilesMatch directive containing a SetHandler which lets httpd know to let these files go to mod_php. These two things are completely unrelated to each other.
In other words, you're probably thinking (very cleverly) that you're doing something that's going to make your apache httpd configuration more safe. I assure you that you aren't. Files that don't end in .php won't go through php in that configuration scenario. And since you control what files are named in your webroot, this should not be a concern. Simply don't allow the user to control the naming of files on your server. It's that simple

How to safely prevent uploaded file from being run via PHP on any server?

I noticed that it's possible to run a file via PHP even if its extension wasn't .php, for example file test.xyz.php.whatever.zyx can be still run with PHP even when the extension isn't .php! It just happens to have .php. in the filename, and that's enough for my Apache to run the PHP script.
I tried (as someone suggested) to put this in a .htaccess file on that folder:
php_flag engine off
But it didn't work on my machine.
The only solutions I know for now are:
Rename to known file extension, which is not run via PHP, such as .txt.
Remove all dots from the filename, thus making it extensionless.
But I'm still not sure how these solutions would work on other servers than my Windows server (with Apache).
Is there any other solutions which doesn't need the filenames to be renamed in any way?
for uploading by users I suggest that you upload a folder in a layer above the root path
in this case Only You Have Access To upload folder( In direct addressing)
and an attacker have not access to any files in this folder
Thus you disable an attacker action to run malicious file
To be completely secure, you'll need to do a couple of things:
Set your upload directory above your "public" folder, making it inaccessible from a browser. This setting is in php.ini (php config file). You'll need to restart Apache for this to take effect. On most Redhat / Fedora / CentOS web servers, this can be:
upload_tmp_dir = "/var/tmp/"
OR, on my local Windows 7 WAMP install, it is set to:
upload_tmp_dir = "c:/wamp/tmp"
Disable scripts from running on that directory (c:/wamp/tmp), in .htaccess:
RemoveHandler .php .phtml .php3
RemoveType .php .phtml .php3
php_flag engine off
In your PHP script, get the uploaded file, filter it based on mimetype (not filetype extension), change the filename, and put it into a secured publicly accessible folder. In more detail:
create a whitelist of filetypes, ex: only images (jpeg, png, gif, bmp). This can be done using mime_content_type() http://php.net/manual/en/function.mime-content-type.php or the newer finfo_file() http://us3.php.net/manual/en/function.finfo-file.php
choose a new filename, often it's best to use a random MD5 hash based on the original filename + salt + timestamp.
move it to a public folder, ex: "c:/wamp/www/project_name/public/uploads"
Preferably use an MVC framework, such as Zend Framework, which includes filetype filtering.
If you do all of that, you should be secure. Obviously you'll never be 100% safe, since there are countless obscure exploits targeting PHP, MySQL, the command line, etc, particularly on older systems. On larger company webservers (what I work on), they disable everything, and selectively enable only what is required for the project. With a system such as WAMP, they enable everything, to ease local development.
Good practice for working on a professional project is to get a cloud server account with Rackspace or Amazon, and learn how to configure php.ini, and httpd.conf settings, as well as PHP security best practices. In general, do not trust the users input, expect it to be corrupt / malicious / malformed, and in the end you'll be secure.
First of all you need to understand what happens here:
test.xyz.php.whatever.zyx
Such a file on a webserver on it's own would do nothing. Only added configuration does tell Apache to execute PHP on that file.
So if you remove that added configuration, Apache won't care to find .php in there - be it at the very end or part of a stacked file-extension.
Check which handler you have set for php in your server configuration. Remove it for the upload directory. This then won't resolve any other configuration issues you might have with uploaded files, however PHP files aren't executed by PHP any longer then - which is what you want if I understood you right.
If you've got a problem to find out what this is about, you need to post your PHP configuration in your httpd.conf file and associated Apache HTTPD configuration files for your system.
The directive somebody told you for .htaccess:
php_flag engine off
does only work if you're running PHP as an apache SAPI module.
Instead of php_flag engine off you could remove the handler for PHP files using an .htaccess file for a single directory.
In the directory you are disabling PHP in, your .htaccess should include:
RemoveHandler .php .phtml .php3 .php4 .php5
RemoveType .php .phtml .php3 .php4 .php5
You can likely get away with the below however, depending on which AddHandler types you have configured in your default Apache configuration, which, on windows, should be in C:\Program Files\Apache<version>\conf\httpd.conf
RemoveHandler .php
RemoveType .php
You will also need to ensure that in your main apache configuration file, that the directory containing the .htaccess file is in, is covered by a Directory statement which has AllowOverride FileInfo set. You may wish to consider AllowOverride All if you will be using .htaccess files for other purposes - see the Apache documentation for AllowOverride for an explanation of the differences.
Personally, this is the main reason I no longer upload files to the web server under any circumstances. Instead, I use S3 / Amazon SDK to move the uploaded temp file directly to a bucket on S3 with Private permissions (I use S3, any other CDN will work just as well). If the file needs to be viewed or viewed by a web client, I use a "getter" function of sorts that integrates with the SDK to get the file and display it.
There are just so many uncontrollable variables that come into play whenever you allow any kind of file upload to a web server, it can be difficult to manage permissions, filtering, and even just space. With S3 (or any other CDN), that is all very easy to manage, and all files are effectively quarantined from the server by default.
On Apache you could disable all dynamic handlers for the directory that contains the untrusted files.
SetHandler default-handler
this is not really good answer but hope useful in some special cases ...
you can use mod_rewrite in .htaccess file like this :
RewriteRule ^(.+).xyz.php.whatever.zyx$ index.php?openfile=$1 [NC,L]
and inside your index.php file :
$file = secure_this_string($_GET['openfile']);
include($file.'.xyz.php.whatever.zyx'); # or some other files
remember to see this answer for security reasons StackOverFlow
and in test.xyz.php.whatever.zyx file :
<?php echo 'hello';
now if client requests /test.xyz.php.whatever.zyx file , out put should be 'hello'
A simple regex would do the job
<?php
$a = strtolower($_FILES["file"]["name"]);
$replace = array(".php", ".phtml", ".php3", ".php4", ".php5");
$_FILES["file"]["name"] = str_replace($replace, "", $a);
?>
This works fine on any server
The following .htaccess-code could work and deny access to files containing "php":
<FilesMatch "php">
Deny from all
</FilesMatch>
I could reproduce your issue quite easily on our server. There is a way to fix this, you need to edit /etc/mime.types and comment out lines
#application/x-httpd-php phtml pht php
#application/x-httpd-php-source phps
#application/x-httpd-php3 php3
#application/x-httpd-php3-preprocessed php3p
#application/x-httpd-php4 php4
#application/x-httpd-php5 php5
These lines cause anything with .php in name to be processed.
Once you comment out the entries in mime.types, mod_php config in /etc/apache2/mods-enabled/php5.conf has this entry which correctly only processes files ENDING with .php
<FilesMatch "\.ph(p3?|tml)$">
SetHandler application/x-httpd-php
</FilesMatch>
What is REALLY SCARY is that this is a default config (Ubuntu 10.04 in our case).
EDIT
On Windows the mime.types file should be in apache_home/conf/mime.types

what does .htaccess with line AddHandler php5-script .php do?

I am with new web host. The public_html folder of each domain I create is auto generated with an .htaccess that has the following line:
AddHandler php5-script .php
What is this for?
This just instructs PHP to handle files ending in .php by passing them to the PHP5 interpreter. Without this configuration in place, the web server may serve the files to the end-user's web browser as raw PHP code, rather than executing the code. That raises the dangerous possibility of exposing database login credentials or, or other secrets.
Using the same mechanism, you could configure the web server to parse files with other extensions besides .php as PHP scripts and hand them to the PHP interpreter. This is occasionally done to mask PHP scripts by naming them with .html extensions, for example.
# Interpret both .php & .html as PHP:
AddHandler php5-script .php .html
It tells php to handle any file with .php in the filename, even if it's not at the end. A file named smile.php.gif will be interpereted as a php file, which is bad if you are going to be using an upload script. This is because Apache allows multiple extensions in any order, so gif.php.jpg is the same as gif.jpg.php. I have heard the best way to select the handler is with FilesMatch. Of course if your web host has this in their httpd.conf you would have to 'remove' it using your htaccess before using the FilesMatch if you don't have access to httpd.conf.
The answer is that the htaccess tells the webserver to handle the php as php5-script and execute it.
Regarding the first answer, you will achieve your goal but it is a really bad practice and you should not allow html files to be executed as php due to huge security concerns.

Do PHP files with multiple extensions gets parsed?

I have a habit of making file backups by adding the .bak extension (file.ext.bak).
Imagine if I have a config in PHP, config.php and I want to backup that file by adding the .bak extension, will the file get parsed or will you see the source code if a client accidentally end up at that url? Is it server dependent?
I've tried some tests on a MAMP server but it seems to be parsing
It depends on the server configuration. It is a bad habit to keep those files accessible by browsers anyway, but should you want to, check your httpd.conf for these lines:
<IfModule mod_php5.c>
AddType application/x-httpd-php .php .phtml .php3
AddType application/x-httpd-php-source .phps
</IfModule>
This will tell the webserver that .php files actually contain code to be executed.
You could add the .bak file there (but it remains a bad habit).
Another workaround would be to just rename the file to file.bak.ext
instead).
The best solution remains moving the files to somewhere where the
browser can't access them, out of the document root and other
mappings.
will the file get parsed or will you see the source code if a client accidentally end up at that url?
Usually, you will see the source code because the .bak extension is not registered to be parsed with PHP. Needless to say, this is very dangerous!
Is it server dependent?
Yes. It is possible to configure the server to parse those files, but it's not part of any default configuration I know.
The better solution is to do it the other way round: filename.bak.php

Apache not handling files correctly (Handler Help)

I'm trying to set up my .htaccess file correctly and I'm having an issue.
The only thing my .htaccess file at the moment is:
AddType application/x-httpd-php .php .html .htm
This is included because my server is not parsing php in my html files.
However when this is included in my .htaccess file, when I open a page in my browser, the user is prompted to save or open the file locally.
I believe the answer to my issues is setting up an action to be done (run with php) however I cannot find out the path to my php files.
Any help is appreciated.
You will need to edit the configuration for enabled modules. On a Debian/Ubuntu type system this will be in /etc/apache2/mods-enabled The file you are looking for is php5.conf
So far all you have done is specify that (dot) htm, html or php files should be served -by default- as application/x-httpd-php, and to my knowledge there is not a single web browser that would attempt to interpret such content -- hence the save-as dialog.
Either you could fix your .htaccess file not to be broken (it is broken behaviour to serve html files as application/x-httpd-php), or you could manually output the correct HTTP headers using the PHP header() function.
Unfortunately, everyone seems to love abusing AddType (and then complain e.g. that MultiViews is broken). See this article, please.
This is not supposed to work in all cases. It depends on the AllowOverride directive of the web server.
You shoud specify the AddType in the serveur config file rather than in the htaccess.

Categories