0

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?

Jack_Hu
  • 857
  • 6
  • 17
  • I've updated the question to clarify the issue I'm attempting to describe. According to: http://php.net/manual/en/function.chmod.php - it seems that compiling php in safe_mode will do what I'm after, but I'm looking for a simple implementation that rolling my own php constantly. – Jack_Hu May 31 '18 at 21:45
  • @Nic3500 - This is not a duplicate. That refers to file/folder permissions, this question is about cross-directory apache/php scripting. If anything it's a duplicate of: [PHP - a different open_basedir per each virtual host](https://stackoverflow.com/questions/2781185/php-a-different-open-basedir-per-each-virtual-host) – Jack_Hu May 31 '18 at 21:58

2 Answers2

1

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.

Mr Glass
  • 1,186
  • 1
  • 6
  • 14
  • 1
    So, if I understand that correctly, I can use something like: `php_admin_value open_basedir /var/www/app1/` in the relative `vhost.conf` file, and that will prevent this kind of malicious code? – Jack_Hu May 31 '18 at 21:56
  • Only the malicious code you posted as an example. Not, for instance, shell_exec('/bin/chmod 777 /far/www/app2') – symcbean May 31 '18 at 22:14
  • I actually have: `disable_functions =exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source` in my `php.ini` file, so that's not so much of an issue. – Jack_Hu May 31 '18 at 22:29
  • So as long as you are using a version of php without eval modifier in pcre, not using the IMAP extension, disabled the sendmail_path and disabled overrides by htacess then I'd need to spend a bit of time thinking about how to break your system (like uploading a custom .so file and calling dl() on it). The right way to restrict access is with permissions. – symcbean May 31 '18 at 22:49
  • @Jack_Hu, yes, adding that will limit the access of the Apache/PHP code. Symcbean is correct that there are other opportunities to get around restrictions, but you've already disabled most (if not all) of them. – Mr Glass May 31 '18 at 23:22
1

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)
symcbean
  • 47,736
  • 6
  • 59
  • 94
  • I'm using php-fpm at the moment. So I need to create a separate pool for each rootDir (`/var/www/app1`) and user (`app1`), add that new fpm-pool uid `fpm-app1` to the gid `app1`, with something like directories=`0770` and files=`0640`? – Jack_Hu May 31 '18 at 22:15
  • That's the bunny (yes), but 0750 for dirs – symcbean May 31 '18 at 22:17
  • I am also using MariaDB... Any ideas on how to plug that hole? – Jack_Hu May 31 '18 at 22:20
  • I believe (at least the `LOAD DATA`) needs the `file` permission, which only the `root` and `MYSQL_ADMINISTRATOR` (or whatever the other default user is called) has. All other users don't have it, and also only have access to their specific database (each root directory `/var/www/app1`, etc., has its own db). – Jack_Hu May 31 '18 at 22:27
  • As long as the mariadb user is not a member of any of the appX groups they won't be able to read files with 0640 permissions or write to dirs with 0750 permissions. I merely highlight it as a consideration should you choose to elaborate/refine my suggestion. – symcbean May 31 '18 at 22:33
  • Woah. Never encountered AppArmor before. Looks like it's pretty useful. I'll have to do some learning and try to get to grips with it a little. So is general consensus that using: -- appropriate file/folder permissions for each user:group. -- limiting available functions in `php.ini`. -- limiting database user permissions and uid/gid permissions. -- using individual fpm-pool/fpm-uid for every directory (i.e., vHost). -- a good AppArmor profile to limit the appropriate programs/services/daemons from running outside of where they're needed (if I understand AppArmor correctly?)....... Sound good? – Jack_Hu Jun 01 '18 at 01:04
  • Yes, but you shouldn't need to disable much (any?) of the functionality in php.ini (except sendmail - and you can provide an SMTP interface instead) if you get the permissions right – symcbean Jun 02 '18 at 23:16