Sunday, October 16, 2011

Chroot PHP-FPM and Apache

As mentioned in "A Note on Security in PHP", the PHP security features (safe_mode, open_basedir, disable_functions) can be bypassed. The Stefan Esser’s paper also describe how to bypass the PHP security features. The better alternative for PHP security is chroot PHP-FPM.

With google, you can easily find how to configure PHP-FPM for nginx. But I want the setup for Apache httpd. I found only this two "Install Drupal in php-fpm (fastcgi) with Apache and a chroot php-fpm" and "The Perfect LAMP Stack – Apache2, FastCGI, PHP-FPM, APC". They explain very well for configuring fastcgi and PHP-FPM. But only first link describe about chroot PHP. The method to chroot is somewhat ugly. Why do I have to create a symlink?

After reading Apache and PHP doc, I found the options. We just need to set "doc_root" to a new web path after chrooted and "cgi.fix_pathinfo" to 0 in "php.ini". We can also set these options per PHP-FPM pool with "php_admin_value" directive.


Updated on 11 Aug 2012

Note: I just notice the _SERVER variables related to path are wrong if "cgi.fix_pathinfo" is 0. If PHP application relies on these variables (such as _SERVER["SCRIPT_FILENAME"], $_SERVER["PATH_TRANSLATED"]), it would fail.

Another method is patching PHP-FPM. Here is my quick and dirty patch for PHP 5.3.15 http://pastebin.com/4EFqEgwE. I added "cgi.fix_chrootpath" configuration. Just set it to the same value as "chroot" value in pool configuration. Do not set "doc_root" and "cgi.fix_pathinfo". The "cgi.fix_chrootpath" should be boolean. But I cannot find a method to access "chroot" pool configuration. Last, I did not test the patch much. It works on my Linux box.


Also do not forget to remove "FollowSymLinks" or add "SymLinksIfOwnerMatch" option in Apache httpd configuration. If you omit it, the attacker can use symlink() trick to read files that web user can read.

After doing chroot PHP, you might think the open_basedir and disable_fuctions are useless. In my opinion, open_basedir is still useful. They can prevent from PHP functions to read files from "upload_tmp_dir" and "session.save_path". So attacker cannot use "temporary upload file" and "session file" for LFI.

Last thing that only few people mention, noexec mount option can be used for web data if web application use only PHP.

8 comments:

  1. Have you tried when Apache2 is also working out of a chroot ?

    ReplyDelete
  2. on which distro you've installed php fpm? i can't get it to work.....

    ReplyDelete
  3. Not really help, you change one ugly thing to another one. If you have many customer with many virtual hosts, i can not tell them to fix their doc_root or whatever.

    ReplyDelete
  4. Poor man's PHP environment chroot: http://www.smallbulb.net/2013/303-chroot-php

    ReplyDelete
  5. hi

    I needed to use php fpm but have each vhost run with a separate userid.
    so i created apache virtualhost entries, and created a separate pool configuration file for each host in

    /etc/php5/fpm/pool.d

    and added the 'user' and 'group' values to the individual pool file.

    It works as expected.

    do I still need to add doc_root or do chrooting ?

    ReplyDelete
    Replies
    1. With a separate userid and properly file permission, it is enough to protect malicious php script from a vhost accessing another vhost. But malicious script still be able to do whatever normal user can do.

      so it's up to you. chrooting will make your server more secure. But some application is difficult to be chrooted.

      Delete
  6. This comment has been removed by the author.

    ReplyDelete
  7. Nice Article. But now chrooting of Apache Server is relatively simple in CentOS/RHEL 7. Have a look at Chroot Jail the Apache Web Server in RHEL/CentOS 7

    ReplyDelete