Okay, so let's say I have two virtual hosts in my Apache config. One defines the directories and such for example.com, whilst the other is for second.org. The server root for apache is /var/www/ and the document roots for the two servers are var/www/example and var/www/second respectively. If a PHP script sat inside of var/www/example, it could read the entire system files. It could also read and execute anything inside of the /var/www/ directory. This means a script on example.com could be used to run or read a script on second.org.

I'd like to be able to lockdown each virtual host so that each PHP script can only read /var/www/virtualdomain directory. Kind of like a shared hosting server where if you attempt to run a script such as:

$dir    = '/var/www/otheruser';
$files1 = scandir($dir);
$files2 = scandir($dir, 1);

There are generally two ways of handling this:

  • Running your PHP process as a separate user.
  • Configure PHP to keep within its document-root.

Both have its disadvantages.

Securing PHP will allow you to set a documet_root where a vhost should operate in while enabling PHP's Safe Mode feature. A slightly more dynamic configuration is to use open_basedir (which can be used without Safe Mode) but relies on a correct apache configuration. I don't think any of these configurations are a great securty feature because it does not account for external libraries and makes security dependent on the PHP implementation, not the operating system.

Running PHP as a separate user using Apache will require a third-party module or a specific configuration. Usually PHP is build as a module within Apache, so all PHP scripts run as the same user as the webserver. A module like suPHP or mod_ruid will drop a process from root specific user and continue the request. This will require running apache as root and compilation of some modules, not to mention a possible security hole. I would not recommend these setups.

You can also switch to PHP-FPM using mod_fastcgi or mod_proxy_fcgi. This will require you to setup a PHP-FPM 'pool' for every user you would like to give one or more vhosts. PHP-FPM will run as this specific user and will be set to the specific privileges on startup. You can also make specific PHP (ini) configuration settings for each PHP-FPM pool.

| improve this answer | |
  • You could also mention open_basedir. mod_proxy_fcgi is a valid solution although a little tricky to setup, you can use mod_fastcgi in external server mode instead. +1 for PHP-FPM solution, this not only lets to separate permissions and ini configuration, but also specific resources per web application. – sam_pan_mariusz Nov 22 '15 at 14:32
  • @sam_pan_mariusz: good comments, I have added these! – Joffrey Nov 22 '15 at 14:39
  • I added php_admin_value open_basedir followed by the document root to one of my virtual host blocks then did a test to see if PHP could read any files outside of the document root and it returned nothing. I am assuming using php_admin_value open_basedir could be a good way to go about this then? Unless of course htaccess can override it, in which case I'll try another solution of yours c: – MyNameWouldGoHere Nov 22 '15 at 16:27
  • You cannot set (nor override) php_admin_value config from .htaccess nor ini_set(), so it's OK. Also remember to use disable_functions to block dl(), exec(), shell_exec(), passthru(), proc_open(), popen() and all other functions to load or execute external binaries. Even better - using open_basedir restrict PHP access to only include filesystems mounted with noexec option (you're on UNIX-family system, I'm guessing). – sam_pan_mariusz Nov 22 '15 at 19:00

Run the php processes for each vost in a separate user context and set the filesystem permissions appropriately.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.