Prevent Apache/PHP from running code that affects another vHost - php

THE SITUATION
I have multiple folders in my /var/www/ directory.
Users are created that have control over a specific directory... /var/www/app1 belongs to app1:app1 (www-data is a member of the app1 group).
This works fine for what I want.
THE PROBLEM
If the app1 user uploads a PHP script that changes the file/folder permissions for something in app2s directory structure, the Apache process (as there's only one installed on the server) will be more than happy to run it, as it has the necessary permissions to access both /var/www/app1 and /var/www/app2 folders and files.
EDIT:
To the best of my knowledge, something like, /var/www/app1/includes/hack.php:
<?php
chmod("/var/www/app2", 777);
?>
The Apache process (owned by www-data) will run this, as it has permissions to change both /var/www/app1 and /var/www/app2 directories. The user app1 will then be able to cd /var/www/app2, rm -rf /var/www/app2, etc., which is obviously not good.
THE QUESTION
How can I avoid this cross-contamination of the Apache process? Can I instruct Apache to only run PHP scripts that affect the files/folders that reside within the relevant vHost root directory and below?

While open_basedir would help, there are several ways of bypassing this constraint. While you could break a lot of functionality in php to close off all the backdoors, a better solution would be to stop executing the php as a user whom has access to all the files. To do that, you need to use php-fpm with a separate process pool/uid/gid for each vhost.
You should still have a separate uid for the php execution from the uid owning the files with a common group allowing a default read only access to the files.
You also need to have separate storage directories for session data.
A more elaborate mechanism would be to use something like Apache traffic server in front of a container-per owner with each site running on its own instance of Apache - much better isolation, but technically demanding and somewhat more resource intensive.
Bear in mind, if you are using mariadb or similar, that the DBMS can also read and write arbitrary files (SELECT INTO OUTFILE.../LOAD DATA INFILE)
UPDATE
Rather than the effort of maintaining separate containers, better isolation could be achieved with less effort by setting the home directory of the php-fpm uid appX to the base directory of the vhost (which should contain, not be, the document_root - see below) and use apparmor to constrain access to the common files (e.g .so libs) and #{HOME}. Hence each /var/www/appX might contain:
.htaccess
.user.ini
data/ (writeable by fpm-appX)
html/ (the document root)
include/
sessions/ (writeable by fpm-appX)

You should add an open_basedir directive to each site's vhost file. The open_basedir directive limits the directories that a site can access.
You can read more about open_basedir here.

Related

Prevent cross-site access in LAMP server

Say we have a server with pure LAMP where we created 2 websites. One inside /var/www/site1, another one inside /var/www/site2
Apache's www-data group has read access to both directories.
And that causes a problem: /var/www/site1/grab.php (which runs through http://site1.com/grab.php) can easily read some private data from /var/www/site2/config.php by using some
file_get_contents("/var/www/site2/config.php");
code inside /var/www/site1/grab.php.
Is there Apache-layer way to prevent this?
Without using suexec or another additional installations - just with configuration tuning.
I understand that if www-data has read access to both directories and site1.com is run by www-data, it is clear why it has an access to /var/www/site2/config.php.
But may be there is some easy way to restrict any up directory for each website and forbid them to access any path outside from their DocumentRoot directory.

Apache/CentOS 7: /var/www/html/ owned by root but created files owned by apache - how do I resolve this?

I have a fresh, unmodified install of Apache on CentOS 7. I notice that when I look at the folder permissions for /var/www/html it and it's content is owned by apache. When a file is created, however, its owner and group is Apache.
Though html is owned by root:root, should all of the contents be owned by apache:apache? or [user]:apache with that user belonging to the Apache group? How should I go about this?
Edit:
Another question - do I want to change this? I do not have a very good understanding of file ownership in Linux systems but it seems with this configuration that the newly created files (apache:apache) are prevented from taking action against files that already exist (root:root). This should prevent PHP hacks from being able to manipulate any existing files, right? Is this just the illusion of security though?
Check your /etc/httpd/conf/httpd.conf file and search for user and group [e.g. User apache Group apache]. Those are the owners by default. In your website there is no need too add write permissions for files and folders assigned to user:group, but you can set readable by owner and others in order to be accessible via web.
Updated answer:
The main reason DirectoryRoot (/var/www/html) owned by root is security. You can leave root as owner of files and set group to apache. Regarding security you make sure apache group has read-only access to files [-> One first meassure]. The security is not an illusion. While files are owned by root and do not have rw access from others, it is hard for external attackers to gain write access to files [because this is the most common way to hijack a site].

.htaccess: prevent php scripts from accessing parent/sibling directories

I'm not particularly experienced with .htaccess (outside of simple mod_rewrite, and basic deny/access), and am unsure of how to approach the following issue:
I have a directory structure as follows:
/parentDirectory
/childDirectoryOne
/childDirectoryTwo
I have a domain that points to /parentDirectory (we'll call it parent.com), and seperate subdomains for each of the children directories (we'll call them one.parent.com and two.parent.com respectively).
These are all located on a shared host. I need to be able to grant ftp access to the subdirectories, but the problem is right now, someone could upload a php file to a childDirectoryOne that scans the parent directory, thereby discovering its sibling direcotry, and can then move into the sibling directory and get sensitive information from files (like a dbConfig file).
What I have been attempting to do (with no success so far) is develop a set of .htaccess files that would prevent the scripts in the children directory from accessing the parent or sibling directories. I'm not even sure if this is possible. Unfortunately, my shared host has no support for setting up a chroot jail, so this is my last option for finding a solution (next to purchasing hosting for each and every ftp user so they can't access others information).
It's considered bad practice to allow read, write and execute permissions to a folder to people you don't absolutely trust.
The ability to upload an arbitrary script and execute it on the server is a very big deal (them accessing another folder is the least of your worries). People can completely destroy your server and all sites on it, access your db, overwrite other pages in any site, and the list goes on.
I would recommend disabling php entirely for uploaded files. You can put this in your .htaccess.
php_flag engine off
That being said, if you really want to do it this way, you can use the open_basedir.
<Directory /parentDirectory/childDirectoryOne>
php_admin_value open_basedir "/parentDirectory/childDirectoryOne"
</Directory>
NOTE!
You need to utilize safe_mode too, otherwise with shell(),exec()... you will be hacked.... BUT!! that's not enough. Read here fully - https://puvox.software/blog/restrict-php-access-upper-directory/

How can I allow php to create files with the same ownership as the files that created them?

PHP creates files with apache:apache ownership which seems to be causing issues with other php scripts accessing the file.
How can I allow php to create files with the same ownership as the files that created them?
I've read elsewhere that having safe_mode turned on can affect this but I've turned it off and reuploaded the files and i still get the same issue.
I'm sure this will be a simple question for someone more familiar with apache but I've failed to find the solution by searching around.
Thanks
If ownership matters and multiple users / projects are on the same server, you might want to look into SuExec in Apache: PHP files will then be run by the user indicated in the settings, so default ownership of files is automatically taken care of. It saves a lot of chown/chmod'ing, and the processes run by the user are more easily restricted.
Otherwise, I normally create a group with both the owner & apache, and set the default umask to 007.
If you are using a Windows OS you can start Apache as a service and allow apache to use your own account's permissions when starting.
Try using fileowner ( http://www.php.net/manual/en/function.fileowner.php ) to get the id of the owner of the current script, posix-getpwuid to get the username for that id ( http://www.php.net/manual/en/function.posix-getpwuid.php ) and chown ( http://php.net/manual/en/function.chown.php ) to set the user for the files.
Why go through all the programatic hassle to change the owner? apache.apache is a very insecure owner anyway. Why not just chmod 0777 the file providing read, write, and execute to all owners. This will eliminate the issue.
If you are still having troubles, then you may need to check if open_basedir is on. If that is the case, it is not file ownership or permissions, but location. This basically means you need to put the file in a location that apache/php already has included in their path.
A.M. mentioned chown() above, please be aware that generally chown() can only be used by root and your webserver running account is highly unlikely to be root, that's a very bad idea.
It is possible to setup sudo to allow chown by other users in specific areas and only to specific users. Just have to create a suitable entry in /etc/sudoers, usually by using the visudo program. If you do not have root access yourself, then your hosting provider will have to do this for you, if they will.
For more information: http://www.sudo.ws/sudo/sudo.html

What permissions for PHP scripts/directories?

I am trying to help a friend moving a web-site from one web-hotel to another.
The old place is already closed, I have only a flat tar file of what was in it.
The web site contained HTML docs and one could download a little Java application (to be loaded on mobile phone) to send data to the web site.
The mobile Java application sent a string to URL=<HOST>/php/register.php. This php script included another php script (../inc/db_login.php), which connected to a SQL DB using $link=mysql_connect(). Another file, register.php, did the SQL insert for putting the new sent data in the DB.
My question is basicaly, where I should put this 2 PHP files on the new website and what permissions the directories and files should have?
The old web server obviously had a /php and /inc directories. None of these exists on the new webserver. Should I create them? What permission should they have? I guess the reason for having the password in a separate PHP file was security. The /php and /inc directory probably had different permissions.
The new server has directories:
/httpdos
/httpsdos
/cgi-bin
/conf (and some others probably irrelevant)
My questions
Does the file-extension (.php) mean something to the server: as PHP scripts are "included" in HTML code (between <?...?>, does the server need to look at the file suffix or is it irrelevant? (I understand that the server reacts on the <?...?>, of course)
should the public file (register.php in my case) be placed in the httpdocs/ directory or does the server (apache I think) reacts on something and fetches it in another directory?
Should the PHP script have permission R-X (read and execute), --X (execute) or R-- (read)? From a OS perspective I guess apache is just reading this files, meaning that they should be R--, but this would mean that if PHP service is "stopped" the client would get all the PHP code in his browser(?). I would prefer it being --X but as this is neither a binary nor has a #!, I guess it must be --R?
If the public PHP script can be placed in another dir (e.g /php instead of /httpdocs) what should /php (and the script) have for permission?. I guess the server has to know about this /php directory (or are there usual defaults?)
The PHP script included (../inc/db_login.php, containing SQL password) should not be under /httpdocs I guess. This means that my register.php is including a file which is not under the /httpdocs subtree. Does this work? Does the server need to know?
I understand you may need to know the server configuration. Just assume the default in your answer (and you can tell where it is changed if it is).
Directories must have execute permissions to be usable. Usually this is 0755. PHP scripts run via mod_php are not executed but rather read; 0644 will suffice for this. Directories that must be written to need to be owned by the user the web server is running as. There may be additional concerns regarding permissions, e.g. SELinux, but the above will get you through the basics.
Documents that must not be accessed by other users or external clients should be 0600, owned by the web server user, and located outside the DocumentRoot. Note that running mod_php in Safe Mode will prevent scripts from ever including anything outside the DocumentRoot; a lamentable flaw.
Set php files to 640
For maximum security you should set minimum permissions, which
is 640.
The owner 6 would be the one uploading the files.
The group 4 would be the one serving the file. Make apache a group member.
The nobody 0 means no other users can read this file. It's important since php scripts sometimes have passwords and other sensitive data.
Never allow php scripts to be read by everyone.
Useful commands:
chmod 640 file.php
chown user:group file.php
usermod -a -G group apache
What these commands are doing:
Change ownership of file.php so user can read and write, group read.
Change ownership of file.php, to chosen user name and group name.
Add apache to the group, so that apache can serve the file. Otherwise 640 will not work.
1) Files that end with a .php extension are handed off to the PHP compiler by Apache. If the proper configuration is not set up to do so, PHP files get served up as text files by the server. The Apache configuration line "AddHandler php5-script php" in the httpd.conf file is the PHP5 method of setting this up.
2) register.php needs to be accessible at http://www.example.com/php/register.php, as the java app is looking for it, so in the Apache htdocs folder, there needs to be a "php" folder with the register.php file in it.
3) PHP files need read access by the user that's running the Apache service. Using PHP as an Apache module has no 'service' to speak of that's separate for PHP. Instead the Apache service, when it gets a request for a PHP file, makes a shell call to the PHP binary to parse the file and hand the Apache service the result, which it serves to the client. Only if you were using PHP from the command line (CLI setup) would the scripts need execute permission, and start with a #!/path/to/php-bin line.
4) The requested file (register.php) needs to be in htdocs in order to be served by Apache. If PHP is running with "Safe Mode" disabled, register.php could include a file that was outside the htdocs folder.
5) The path "../inc/db_login.php" is relative to the PHP script that was originally fetched (register.php), so, since register.php is in htdocs/php/register.php, that would put db_login.php at htdocs/inc/db_login.php.
I've coded a function to address the permissions issues in both of PHP / SuPHP and similar:
function realChmod($path, $chmod = null)
{
if (file_exists($path) === true)
{
if (is_null($chmod) === true)
{
$chmod = (is_file($path) === true) ? 644 : 755;
if (in_array(get_current_user(), array('apache', 'httpd', 'nobody', 'system', 'webdaemon', 'www', 'www-data')) === true)
{
$chmod += 22;
}
}
return chmod($path, octdec(intval($chmod)));
}
return false;
}
Maybe it's useful for you.
All the PHP files which are intended to be addressed directly via URLs can happily reside in the same directories as the static content (this is the usual practice).
It is good practice to have at least one directory outside those visible from the webserver to hold include files, but the PHP include path should still include '.'.
I'd recommend not putting lots of non-standard directories in your root filesystem - the default webroot varies by distribution, but I usually go with something like:
/var/www/htdocs - as the document root
/usr/local/php - for include files
Obviously if you intend running your webserver chrrot, these should be mapped accordingly.
All files must be readable by the uid under which the webserver runs, however if you can restrict what is writeable by this uid as much as possible then you close off a potential attack vector.
I usually go with setting up my dirs as drwxrwSr-x owned by a member of a webdev group with the group ownership as the webdev team, (the httpd uid is not in the webdev group) and files are therefore -rw-rw-r-- So anyone in the webdex group can change files, and the httpd uid can only read files.
1) does the files-extension (.php) means something to the server:
Yes - go read the PHP installation guide.
C.
Assuming your SFTP/FTP user is johndoe and web server group is www-data. johndoe only read, write the files but not execute the files (in my case never). The web server software usually Apache/Nginx from the group www-data can read/write/execute the files. Other users? what are they doing here???
So, I used to set 0670 (rw-rwx---) and works for me always :)
Set file permission to 0644 and folder permission to 0755.
I have coded a library for that.
Example of usage:
<?php
use MathiasReker\FilePerm;
require __DIR__ . '/vendor/autoload.php';
(new FilePerm([__DIR__])) // <-- root directory
->setDefaultModeFile(0644) // <-- file permission
->setDefaultModeFolder(0755) // <-- folder permission
->scan()
->fix();
Full documentation: https://github.com/MathiasReker/php-file-permissions

Categories