Bring life to a barren, technological wasteland

Locking Down PHP

The most important sites that I need to migrate from Joyent to Linode are PHP sites, primarily my Wordpress multisite network. I’ve been dragging my feet on it though, because I want to be paranoid about security and I couldn’t figure out how to be properly paranoid with PHP.

After all, the web server needs to have read access to all of the files. The PHP interpreter needs to have read access to all of the files. And, for several sites, the PHP interpreter needs to have write access to both files and folders. But if the PHP interpreter has write access to the files then one poorly written script can give an attacker write access to those files as well. The last thing I want is for a bug in one PHP application to cause destruction across all of my PHP applications.

Today, I think I finally figured out how I want my PHP setup to work. I was searching the Linode forums for inspiration and I found this post from hybinet. Extrapolating from that post, there are several things that I want to do.

  1. Setup nginx to run under its own user account, as a member of a group that has read access (but not write access) to the entire web hierarchy.

  2. Create a separate user account for each PHP application. Make that application’s files readable and writeable by that user and readable by the nginx group.

  3. Setup a separate PHP instance for each application. Have PHP run as that user, with read and write access to that user’s files and that user’s files only.

  4. Use the open_basedir directive to lock PHP down to the specific application’s folder. Don’t let it exit that file hierachy for any reason.

With this setup, if an application gets hacked, the attacker will have access to one specific user account and one specific, limited, set of files. A successful attack against one application won’t automatically result in all applications being attacked.

The big question I had was how to manageably set up a separate PHP instance for each application and manageably limit PHP to a specific application root. That’s why I was ecstatic when I learned about PHP-FPM (FastCGI Process Manager). It’s a new (as of PHP 5.3.3 and PHP 5.4) FastCGI implementation. Among its features is the ability to start workers with different uid/gid/chroot/environments and the ability to start workers with different php.ini files.

I can easily configure the PHP-FPM configuration file with entries for each application, limiting the user account and application roots. Then I can configure nginx to direct PHP scripts for each application to that application’s specific pool of PHP-FPM workers. The result will be a centrally managed PHP setup that can have limited security for each application.

The theory sounds fantastic. Now I just have to work on actually setting it up for a test PHP application.