Using Apache to better secure WordPress

Securing WP with Apache

Needless to say, WordPress can be a beast at times. Just ask some of the web developers around Asheville. It can also be a pain to deal with security-wise because WP is a third party application built on other applications (i.e. PHP, Apache, MySQL) and all of these parts to the system need constant attention to avoid issues in security of your web presence.This is why I decided to start a series of posts to help demonstrate how WP can be locked down without affecting the needs of your web customers (per say).

In this first part in the series, I would like to explain how to lock down WP in several ways. Primarily, we will be dealing with Apache configurations and some internals to WP to accomplish this feat. But, in the end, you will see that you will still be able to use WP fully and perhaps even safer than before.

Where to begin: defining roles of users of WP.

When most developers setup WordPress, they do not think about the roles of the users using the system. There are fundamental differences between the authors, developers and visitors of the site in most cases, which is a major reason for using WP. But, one should also think about a separation even on the system level to help secure your WP installation. Before we start to configure the system and WP itself, ensure you have a clear understanding of whos who and who will be using WP in what ways. This will help you define the best system layouts later.

The plan for the WP system

Since we now have a clear understanding of those people that will be using WP and their roles on the system, we should be able to use this to draw up a good design for the WP system on a whole. For our examples in this series, we will assume the following…

  1. Visitors to the WP site can come from any place online and have the ability to read entries. Entries are normally business related information for the company.
  2. Authors of the primary content for the WP site are located in a home office (all one network). These guys post the actual content on the site.
  3. Developers and administrators of WP are on the same network as the authors.
Plan

Plan

A good start to our plan is to draw out how the system will look in the end. Here is my drawr’ing based on the above assumptions. As you can see, there is a clear separation of roles for the users and this justified the separation of the systems as well. This also allows us to better protect our WP environment by restricting what actions can be performed in each instance. For example, the admins and authors on the corporate LAN will be able to post entries and upload content as usual. But, users outside of the corporate environment will need to upload/post to a different system which but it will all talk to the same database in the end. This is important from a security prospective because if someone were to attack the more hardened, public instance of WP visible to external users, then this would largely not affect the entire system.

You should not stop at just defining the system bounderies and roles, you should also start to think about how you are going use WP. This normally includes some use of third-party plugins to WP. You should be aware though that the number one security issue with using WP is normally dealing with plugins. So, keep the plugins to a minimum and ensure that any plugins you use should have good support and be updated when necessary.

Yes, this plan does require more investment, not only in setting it all up, but also in training and administration costs of running 2-3 systems for WP — rather than the traditional 1- system-does-everything approach. But, notice we are creating more freedoms for the authors/admins (who normally need it) and more security on the side of the users (visitors) of the site by logically separating them and their roles. This plan works on more corporate/government/small business environments, but may not work for some shops. Adjust where necessary, but try to keep the separations if possible.

Apache in the mix

We are going to setup two Apache instances. The first is a standard instance for the admins and authors within the (hopefully) locked down corporate environment. The other instance of WP is a more locked down version which talks to the same database as the internal instance for admins/authors/developers.

Firstly, use the Directory and/or Location directives to lock down the public instance(s) of WP for all files in the wp-content, wp-includes, and wp-admin directories. In this example, we will also lock down the wp-login.php page since this will not be used by external folks…

<Directory “/var/www/html”>

AllowOverride None

Options None

</Directory>

<Directory “/var/www/html/wp-content”>

Order Deny, Allow

Deny from all

<FilesMatch “\.(jpg|jpeg|gif|png|css|js)$”>

Allow from all

</FilesMatch>

</Directory>

<Directory “/var/www/html/wp-includes”>

Order Deny, Allow

Deny from all

<FilesMatch “\.(jpg|jpeg|gif|png|css|js)$”>

Allow from all

</FilesMatch>

</Directory>

<Location “/wp-login.php”>

Order Deny, Allow

Deny from all

</Location>

There is an uploads directory as well for WP located in the wp-content directory. For all purposes and instances of WP — this should be moved out of web root (where WP is installed). You should move this by doing the following…

  1. Create a directory in /var/www called uploads.
  2. Setup an Alias via Apache configuration to point to this new uploads directory.

Alias /var/www/uploads /wp-content/uploads

Now, we can set up some permissions on this more protective upload container…

<Directory “/var/www/uploads”>

Order Deny, Allow

Deny from all

<FilesMatch “\.(jpg|jpeg|gif|css|mov|mp4|mpg|avi)$”>

Allow from all

</FilesMatch>

</Directory>

By moving the uploads directory from web root, we are mitigating some attack vectors like Remote File Inclusion (RFI) and Local File Inclusion (LFI) which have popped up from time to time within WP. You will also need to tell WP where the new uploads directory is via the PHP — but we will get to that later when we actually install WP.

We have setup Apache for the public instance to be largely locked down and still allow content to be driven from inside the company. Next time, we will talk about the MySQL configurations to think about when deploying WP and later on we will be actually installing WP with these configurations.