WordPress Security Tips

Search Google and just about every article you come along will tell you that in order to have a secure blog, you need X amount of plugins. I disagree. I use none yet I’m satisfied I have a reasonable level of security. I use a number of techniques to keep the site safe, which I’ll discuss over the course of the post.

1. Restrict access to wp-admin by IP

Something I started doing recently is only allowing my IP to access the wp-admin directory. This stops someone taking the site by brute force (unless they’re on my PC!) and ensures that only I can control the site the easy way. Of course, the database is still relatively vulnerable, but this is a fairly good way of stopping attacks at the front door:

<Files wp-login.php>
Order deny,allow
Deny from All
Allow from 123.456.789.0

2. Super strong database password.

Using the cPanel password generator, I can create a fairly secure database password, something vitally important. If I hacker had access to the database, they can do anything. Quite literally. A second step I take is to always rename the database from the Fantastico generated name as Fantastico always generates a wp_ style name, making the site easily identifiable as running WP. Doing so is fairly easy manually although this is one of the few times I’d recommend a plugin; the security scan plugin can rename your database in a single click.

3. Protect wp-config.php

With a strong database name and password, you obviously now need to protect the file that contains these. The following .htaccess code does the trick by preventing access to the most important file you’ve got.

# protect wpconfig.php
<files wp-config.php>
order allow,deny
deny from all

Another interesting trick from site is to move the sensitive data in the wp-config.php to an unreachable location (ie below www in your directory) and then do a PHP include to the sensitive information – I found this on DevLounge and it’s actually quite clever if you think about and certainly something to look into more closely (ie read the post linked to).

4. Be careful with plugins

Plugins are often a way into your blog. Something badly coded can be a backdoor for hackers – for that reason you should always be careful about the plugins that you use. I personally limit myslef to ten plugins and popular ones at that that are less likely to have a hole in them (making the presumption that they’re good so they must be well coded) and that as they’re popular if a problem is found an update will be released in good time. Plugins which want updating a lot go, regardless of how useful the functionality may be.

5. Use SSL if you can

A favourite of list posts about WordPress security is to say how important using SSL is and here’s a plugin to use it. I’ll explain a bit more. Essentially, SSL or secure socket layer is encrypting your data. That does mean by standard your WordPress password is being sent with no protection at all and so could be intercepted with relative ease by a hacker. If your web host offers an SSL certificate, take it and use it (with one of the plugins available). If it doesn’t offer you a certificate, certainly seriously consider tip #1. The codex has some excellent info on this subject.

6. Keep users in check.

Now that you’ve got a super secure site, safe from attack from the outside, now it’s time to like at the inside. You thought you could trust John to write stuff? Turns out he’s inserting dodgy links in your theme and using your server to host his images. This is all relatively easy to stop – you just need to be very careful what permissions you give other users in the first place. WordPress by default has a number of user options – Subscriber, Contributor, Author, Editor and Administrator. It’s so so important that you get these permissions right as if you don’t then John has the power to wreck your blog. There are also a number of plugins available which allow you to customise user permissions – Justin Tadlock’s members plugin and the role manager plugin, which is my personal favourite; install it and it lists just about every single permission there is and offer you the option to add or remove it. As Justin Lee Collins might say, “good times!”

7. Stay up-to-date

New WordPress releases are frequent and often the upgrade is a security fix, so staying up-to-date with the new releases is paramount. Staying updated is as simple as clicking the upgrade button when a new version of WP is available, but before you do that, make sure you’ve backed up. Doing so is really easy with the WordPress Database Backup plugin which you can set to email backups to an email address (set up a Gmail account specifically for this purpose) at regular intervals — mine backs up every day to my email, not my hosting.

8. Protect the installation files

Big thanks to Jeff Starr for his help with the rest of this post – I wanted to make sure I had a good range covered, so Jeff kindly pointed me in a couple of different directions, which includes his “Important Security Fix for WordPress“, essentially pointing out that the install.php file may display to anyone if your server goes down, allowing said anyone to completely reinstall WordPress on your site and have control of it too. Bad times. Thankfully, there’s a blissfully easy solution: delete the install.php file. FTP (that is a verb :P) into /wp-admin/ and delete the install.php file and you’ll have that street of vulnerability closed.

9. Stopping spam

The next point Jeff pointed out was stopping spam and the well recognised way to do this is to stop annoying scripts with the stopping no-referrers technique:

#Stop annoying spammers
<IfModule mod_rewrite.c>
RewriteCond %{REQUEST_URI} .wp-comments-post\. [NC]
RewriteCond %{HTTP_REFERER} !.*wpshout\. [OR,NC]
RewriteCond %{HTTP_USER_AGENT} ^$
RewriteRule (.*) - [F,L]

Obviously you’ll need to change wpshout to your domain.

10. Remove error messages from the login screen

Finally, this is a great tip that goes in your functions.php file and removes error messages from the login screen – thus hackers wouldn’t know if the username or password was incorrect. Clever!

add_filter('login_errors',create_function('$a', "return null;"));