Saturday, April 13, 2013

Webserver Security Model

Hey all!

Over the course of the week I had thought long and hard about how I wanted to rebuild my Linode VM to accommodate some of the changing realities of what I want out of my hosted Linux solution. One of the key changes I wanted to make was to try and use NGINX over Apache for the webserver due to the reputation it has gained for resource utilization in virtualized environments. And I'm always up for playing with new things...

Then it got me thinking about the security model of virtual hosted sites in Apache. One of the things I've always disliked is that under a default LAMP stack installation, documented on a Server Guide on Ubuntu's site, that all shared websites are run under the security context OF THE SAME USER ACCOUNT ON THE SYSTEM.

What this essentially implies is that code executed under one site could potentially impact all other hosted sites on this Apache server. I'm not a huge fan of this model, and it's not a model that IIS follows when running ASP.NET-powered websites.

I'm going to try and demonstrate this using some charts I made for this blog post to kind of provide a visualization to this issue. I'm not all that great at chart making so I hope this helps. Just remember--the colors imply separation of security contexts. Also, assume all security permissions are set for RW for the owner, and R for everything else.

libapache2-mod-php5 Problem

The underlying problem to this issue is that when Apache loads, it will launch the root process which handles incoming requests and controls the worker processes. The worker processes are the ones that actually carry the workload of a particular request. These worker processes are spawned under a limited user, usually www-data in Debian-based distributions, and http or apache in others.

Each worker process has also loaded the PHP library, which executes dynamic code located in the .php files in your website. All of this code is run under the context of the worker process, which in this case is shared across all of your virtually-hosted websites.

Under this security model, a website that is vulnerable to attack on could potentially write code to another website on the same server,

This is visually demonstrated below:

If someone were to exploit exploit-me.php, they could write some extra dynamic code in index.php on the other site.

The Solution

Obviously there are many potential solutions to this problem, but I'm going to try and stick as closely to the original configuration as possible--that is, a single VM node running multiple shared hosted websites.

The proper way to solve this particular issue is to leverage FastCGI, or more specifically, PHP-FPM, to handle the execution of dynamic code for you. You can use PHP-FPM even with Apache. A guide of which can be found on the Apache Wiki.

Application Pools

A model that IIS has used for a while is the concept of an Application Pool. This model is also adhered to by PHP-FPM, and I'd highly recommend you familiarize yourself with its proper configuration.

When configured properly, dynamically executed code is run under independent processes and security contexts. This essentially means that code on domainA could not write to files hosted on domainB. In the TechNet link above, Microsoft has outlined a few additional benefits of operating under different processes. If ProcessA hangs, ProcessB can still execute code. Obviously you are bound to within hardware and threading limits, but the point still stands.

Below is a diagram outlining how this model differs from the one above:

As you can see above, and now have their own independent user accounts along with their own independent processes. In the NGINX/PHP-FPM model, the communication between the webserver process and the PHP-FPM process is done with Unix Sockets. Each PHP-FPM Pool is listening on its own unique socket. The socket to use is defined in NGINX's configuration under the server (vhost) configuration.

Even more importantly, you can use this process model to implement Mandatory Access Control with something like SELinux, the details of which are far beyond the scope of this document.