WordPress and Server Hardening – Taking Security to Another Level

The biggest problem today with most content management systems (CMS) and web applications is the adoption of what we call the “Win95 security model”. Do you remember the Windows 95 security model? With everything running under the admin role? No separation of privileges? No separation of processes? One vulnerability and you take it all?

Confused as to how this relates to today’s CMS’s (including WordPress, Joomla, and others)? Let us explain using WordPress as an example (most popular CMS out there):

  1. The user that is running WordPress (including any plugin or theme) can modify any file on the site.
  2. Any URL can be accessed directly, even when they are not supposed to be used that way.
  3. The admin panel (wp-admin) runs in the same domain and within the same codebase/permissions as the rest of the application.
  4. Admin users can install any plugin/theme, which can then modify any file and change anything in the database
  5. Most users log in as admin, even though they don’t need “admin” access most of the time.
  6. Every plugin and theme has the same level of access (and permissions) as the core of the application (no separation of privileges).

Yes, this is the default and most common way to install WordPress, specifically on shared hosts. Why you ask? It is easy to install and configure, but definitely not to be confused with the correct or secure approach to installing any application.

Imagine, it’s like having one username and password for all your accounts… oh… wait…

Improving Your Security Posture

I should preface this by saying that this won’t apply to shared environments, sorry… :(

But if you’re on a dedicated (or VPS) environment you’re in luck so read on.

1- Correcting Server Access Control

The user running WordPress (generally www-data or apache) should not have permissions to modify any file.

That protects you in case there is a vulnerability in any plugin, theme (or even in WordPress itself), since they won’t be able to modify anything.

Fortunately, there is an easy fix but one that many won’t use. In most instances WordPress is running as apache/apache, default webserver roles, and what you want to do is create a new user that will assume that role, disallowing the webserver user from having those rights.

To do this, this is what you have to do:

# adduser wordpressuser
# cd /var/www/pathtoyoursite
# chown -R wordpressuser .
# chmod -R 750 .
# chgrp -R apache .

This makes it so that only the wordpressuser user is the only one with with write permissions to your site directory.

Now, we all know that the only directory that needs to be writeable is the uploads directory in WordPress. So, to accomodate this we make some slight modifications that adds a rule allowing our beloved Apache user to write to that directory:

# chmod -R 770 ./wp-content/uploads/

Now, to ensure that we’re taking every precaution possible we turn to our .htaccess file to protect us from the injection of backdoors. You’ll want to create the .htaccess file inside the /wp-content/uploads directory:

php_flag engine off

and

<Files *.php>
deny from all
</Files>

InfoSec is about risk reduction, by taking these additional steps you have now greatly reduced the inherent access control risk associated with default WordPress installations. Do note however that this is not isolated to WordPress, these can also be applied to Joomla, Drupal and other such CMS applications.

Disclaimer for my colleagues: Doing this change will require you to take a more proactive approach to the administration of your site. You won’t be able to use the pretty GUI’s WordPress offers you, you’ll have to manually update your core, themes, and plugins. But trust me, it’s ok, it’s only slightly inconvenient.

2- The Accessibility Challenge

WordPress has many files, but very few of them need to be accessed directly by the users. To prevent files being accessed directly, we recommend blocking direct PHP access to /wp-content with the following additions to your .htaccess file:

<Files *.php>
deny from all
</Files>

An example of how this would have been useful, let’s think back to the TimThumb outbreak last year or even this year’s Uploadify discussions. Killing the execution of PHP in /wp-content would have and will protect you from both these known vulnerabilities.

3- Correcting Application Access Control

The admin panel (wp-admin) runs on the same domain and same privileges as the rest of the application. In a perfect world, it would be isolated, but to minimize issues, we recommend adding two restrictions to wp-admin access (via .htaccess):

3.1- Only allowing certain IP addresses:

order allow, deny
allow from IP1
allow from IP2
deny from all

3.2- Adding an additional user/pass (pre-authentication):

AuthUserFile /var/www/mysite/.htpasswd
AuthName “Site private access”
AuthType Basic
require user myuser2

By adding those two restrictions, you isolate wp-admin, requiring additional permissions and again, improve the security model. Hope you’re starting to get the trend of the post.

4- Restrict admin access to only required users

On the old days of Windows, everyone was admin. Don’t do the same on WordPress. If someone needs to write posts, they only need author permission. If someone needs to edit/post articles, he only needs editor permission.

There is a reason that out of the box WordPress provides varying degrees of roles and associated permissions, use them. We realize they may be a bit complex and difficult to understand, hopefully this helps:

  • Administrator – can do everything
  • Editor – They write stuff, more importantly they can publish
  • Contributor – The Author’s cousin, but they can’t publish
  • Subscriber – They follow your rants about your favorite past times but can’t do anything else

Logging in as Admin for every task is foolish, don’t be that person.

Summarizing the journey

Above we addressed 4 steps, that if employed, covers 5 distinct sections in the security model I prefaced the post with:

  1. The user that is running WordPress (including any plugin or theme) can modify any file on the site
  2. Any URL can be accessed directly, even when they are not supposed to be used that way
  3. The admin panel (wp-admin) runs in the same domain and within the same codebase/permission as the rest of the application.
  4. Admin users can install any plugin/theme, which can then modify any file or change anything in the database
  5. Most users log in as admin, even though they don’t need “admin” access most of the time

By employing some, ok all of the recommendations above you have effectively disabled WordPress from modifying its own files, admin users no longer have write permission to all files, and the themes / plugins can’t modify everything. Why are these three areas important? Well, because they are the most exploited vectors to date.

If you think this is all, you’re wrong, I would prefer to see updates where the plugins / themes no longer have the same level of permissions as the core of the application and their ability to have full database access (read/write) are dismissed, but, I don’t want to give the appearance that I’m paranoid.

But seriously, in a perfect set up, you would have at least 2 database users, one configured on wp-admin with write access, and one for the rest of the site with only read access. I’m just saying..


If you have any questions or more ideas about this model or how to improve it, let us know.

Scan your website for free:
About Daniel Cid

Daniel is the Founder & CTO of Sucuri and also the founder of the open source project - OSSEC HIDS. His interests range from intrusion detection, log analysis (log-based intrusion detection), web-based malware research and secure development.

You can find more about Daniel at his site dcid.me or on Twitter: @danielcid

  • Pingback: Wordpress : Add an admin user to database and Reset User Roles – Smashing Web()

  • Pingback: WordPress Security Threats - Jul/2012()

  • Pingback: WordPress Security – Cutting Through The BS | Sucuri Blog()

  • Pingback: Protéger son Wordpress | memorandom.org()

  • 2so

    Hey Daniel, thanx for these nice quick fixes, however i found I’m having a problem with one of the .htaccess fixes. In the fix for the wp-content folder. When i add the .htaccess file with the code below:

    deny from all

    I notice the my images are no longer showing up. I think this is because a php file is used to create the thumbnails on my site. I’m not sure which php file it is but i’m guessing allowing only that php file should fix the problem….

  • http://www.8ravens.com 2so

    I don’t know if this is correct .htaccess syntax but it does seem to show the thumbnails now after i added thumb.php(file i found in my theme folder) to my .htaccess file. The new file looks like this:

    deny from all

    Allow from all

  • http://www.seojeek.com/ Alex Vallejo

    “we all know that the only directory that needs to be writeable is the uploads directory in WordPress”.

    Um, no. You need the plugins folder to be writeable if you want to install plugins from the WordPress admin. You need .htaccess to be writeable if you want pretty permalinks.