Reducing Risk with WordPress

Saturday, October 18, 2014

WordPress has evolved from a blogging platform into a development framework. It is becoming increasingly common to see it used as a basis for a variety of software projects, including e-commerce stores. Its ease of use and low barrier to entry means it has rapidly become a favourite.


Unfortunately, as with every popular software system, it has become a target for hackers, spammers and other nefarious types on the Internet. WordPress sites are responsible for a large number of the phishing and malware pages online.


If you're running a website, your site will be a target eventually, no matter how big or small. Malicious users run automated web crawlers (like what Google uses to discover content) to discover and scan zillions of websites looking for vulnerabilities. WordPress is relatively easy to detect, so it's not if your site is targeted by hackers - it's when.


Is WordPress Insecure?

 

Why is this the case? Is WordPress fundamentally broken or insecure?

 

The short answer is "no". The longer answer is "no, but… sometimes".

 

There seem to be two major factors that influence WordPress security: plugins and

passwords.

 

The Risk of Plugins

 

One of the best features of WordPress is that it is easily extensible: it can be modified and adapted easily by means of powerful plugin and theming systems.

 

If you run a WordPress site, you almost certainly have some plugins installed to extend the functionality - maybe a contact form so people can send you email, maybe a spam filter. There is simply a staggering number of plugins, made available because WordPress is easy to develop for, and they're dead easy for anyone to install.

 

Unfortunately, as with all great power, it comes with great responsibility. It is very important to note that any random WordPress plugin can wield enormous power on your site. The very features that make them so useful also make them so risky. A malicious plugin could track user or admin activity and report it to remote sites.

 

Genuinely malicious plugins, however, are (probably) pretty rare. Much more common - and certainly responsible for the majority of websites getting hacked or otherwise compromised - are plain old buggy plugins. A plugins with a simple coding error - a character in the wrong spot, or the wrong function call used, or one not used - can mean your entire site is an open book to malicious users. They can read all your data, and - possibly worse - write over it.


Many plugins simply increase the attack surface of a WordPress site - it creates more opportunities for a malicious user to compromise your website.


(It should also be noted that a lot of the problems that apply to plugins also apply to WordPress themes. A theme is basically just a bunch of code. Many themes include plugins, but don't forget that a theme with a bug in it can also cause a lot of problems.)

 

The Risk of Passwords

 

Everyone knows this one, so I won't spend too much time on it. Passwords are hard. Everyone wants a password that's easy to remember, but these are typically very weak. Longer passwords are better, but harder to remember. There's the correct horse battery staple method, but then you've got people saying that's no good either. Argh!

 

Putting that aside for a minute, let's take a look at a real-world example of what is going on when people try to hack your WordPress site by brute forcing your password.

 

The below is a (small!) excerpt from a authentication log file showcasing a concerted attempt to brute force the passwords on a (small, non-descript, personal) WordPress blog. The sheer volume of requests is interesting - the excerpt doesn't show them all, but there were thousands over the course of a 24 hour period - as is the fact that they come from a large number of different IP addresses (presumably some sort of botnet).

 

Sep 18 06:36:33 testvps wordpress(example.com)[11218]: Authentication failure for Administrator from 85.97.168.XX
Sep 18 06:36:50 testvps wordpress(example.com)[11225]: Authentication failure for Administrator from 124.120.10.XX
Sep 18 06:36:59 testvps wordpress(example.com)[11232]: Authentication failure for Administrator from 186.18.60.XX
Sep 18 06:37:01 testvps wordpress(example.com)[11239]: Authentication failure for example.com from 173.161.124.XX
Sep 18 06:37:14 testvps wordpress(example.com)[11246]: Authentication failure for example.com from 216.195.240.XX
Sep 18 06:37:50 testvps wordpress(example.com)[11247]: Authentication failure for admin from 123.176.17.XX
Sep 18 06:37:55 testvps wordpress(example.com)[11254]: Authentication failure for admin from 121.96.42.XX
Sep 18 06:37:58 testvps wordpress(example.com)[11255]: Authentication failure for example.com from 109.74.73.XX
Sep 18 06:38:06 testvps wordpress(example.com)[11256]: Authentication failure for example.com from 95.12.97.XX
Sep 18 06:38:06 testvps wordpress(example.com)[11257]: Authentication failure for example.com from 95.12.97.XX
Sep 18 06:38:10 testvps wordpress(example.com)[11258]: Authentication failure for admin from 189.133.143.XX
Sep 18 06:38:10 testvps wordpress(example.com)[11259]: Authentication failure for admin from 189.133.143.XX
Sep 18 06:38:32 testvps wordpress(example.com)[11266]: Authentication failure for admin from 111.91.86.XX
Sep 18 06:39:29 testvps wordpress(example.com)[11274]: Authentication failure for admin from 166.147.104.XX
Sep 18 06:40:11 testvps wordpress(example.com)[11291]: Authentication failure for example.com from 187.199.59.XX
Sep 18 06:40:33 testvps wordpress(example.com)[11292]: Authentication failure for admin from 197.34.170.XX
Sep 18 06:42:19 testvps wordpress(example.com)[11440]: Authentication failure for example.com from 98.89.84.XX
Sep 18 06:42:31 testvps wordpress(example.com)[11448]: Authentication failure for example.com from 177.138.120.XX
Sep 18 06:42:49 testvps wordpress(example.com)[11556]: Authentication failure for Administrator from 76.76.172.XX
Sep 18 06:43:01 testvps wordpress(example.com)[11614]: Authentication failure for admin from 216.195.240.XX
Sep 18 06:43:06 testvps wordpress(example.com)[11630]: Authentication failure for Administrator from 119.35.25.XX
Sep 18 06:43:14 testvps wordpress(example.com)[11637]: Authentication failure for admin from 95.12.97.XX
Sep 18 06:43:14 testvps wordpress(example.com)[11638]: Authentication failure for admin from 95.12.97.XX
Sep 18 06:43:53 testvps wordpress(example.com)[11653]: Authentication failure for example.com from 173.26.69.XX
Sep 18 06:43:53 testvps wordpress(example.com)[11652]: Authentication failure for example.com from 173.26.69.XX
Sep 18 06:44:29 testvps wordpress(example.com)[11717]: Authentication failure for {domain} from 218.19.118.XX
Sep 18 06:44:30 testvps wordpress(example.com)[11718]: Authentication failure for {domain} from 218.19.118.XX
Sep 18 06:44:32 testvps wordpress(example.com)[11719]: Authentication failure for example.com from 41.68.153.XX
Sep 18 06:44:37 testvps wordpress(example.com)[11720]: Authentication failure for example.com from 188.169.172.XX
Sep 18 06:44:37 testvps wordpress(example.com)[11721]: Authentication failure for Administrator from 119.139.169.XX
Sep 18 06:44:38 testvps wordpress(example.com)[11722]: Authentication failure for Administrator from 213.6.0.XX
Sep 18 06:44:55 testvps wordpress(example.com)[11735]: Authentication failure for admin from 41.35.26.XX
Sep 18 06:45:00 testvps wordpress(example.com)[11736]: Authentication failure for admin from 187.199.59.XX
Sep 18 06:45:28 testvps wordpress(example.com)[11746]: Authentication failure for admin from 176.121.227.XX
Sep 18 06:46:00 testvps wordpress(example.com)[11747]: Authentication failure for example.com from 41.233.203.XX
Sep 18 06:46:45 testvps wordpress(example.com)[11749]: Authentication failure for Administrator from 197.34.170.XX
Sep 18 06:47:47 testvps wordpress(example.com)[11757]: Authentication failure for Administrator from 216.195.240.XX
Sep 18 06:47:52 testvps wordpress(example.com)[11765]: Authentication failure for example.com from 125.22.195.XX
Sep 18 06:48:14 testvps wordpress(example.com)[11768]: Authentication failure for admin from 108.12.237.XX
Sep 18 06:48:44 testvps wordpress(example.com)[11771]: Authentication failure for admin from 173.26.69.XX
Sep 18 06:49:15 testvps wordpress(example.com)[11778]: Authentication failure for admin from 188.169.172.XX
Sep 18 06:49:34 testvps wordpress(example.com)[11781]: Authentication failure for Administrator from 187.199.59.XX
Sep 18 06:49:37 testvps wordpress(example.com)[11788]: Authentication failure for Administrator from 175.17.156.XX
Sep 18 06:49:41 testvps wordpress(example.com)[11795]: Authentication failure for admin from 177.138.120.XX
Sep 18 06:50:09 testvps wordpress(example.com)[11804]: Authentication failure for example.com from 79.12.237.XX
Sep 18 06:50:24 testvps wordpress(example.com)[11806]: Authentication failure for example.com from 151.240.180.XX
Sep 18 06:51:27 testvps wordpress(example.com)[11809]: Authentication failure for Administrator from 63.227.69.XX
Sep 18 06:51:44 testvps wordpress(example.com)[11817]: Authentication failure for Administrator from 108.12.237.XX
Sep 18 06:52:10 testvps wordpress(example.com)[11824]: Authentication failure for admin from 109.74.73.XX
Sep 18 06:53:12 testvps wordpress(example.com)[11826]: Authentication failure for example.com from 212.252.101.XX
Sep 18 06:53:12 testvps wordpress(example.com)[11827]: Authentication failure for example.com from 212.252.101.XX
Sep 18 06:53:32 testvps wordpress(example.com)[11829]: Authentication failure for Administrator from 188.169.172.XX
Sep 18 06:53:54 testvps wordpress(example.com)[11838]: Authentication failure for admin from 125.22.195.XX
Sep 18 06:55:03 testvps wordpress(example.com)[11852]: Authentication failure for admin from 203.193.153.XX
Sep 18 06:55:03 testvps wordpress(example.com)[11853]: Authentication failure for admin from 203.193.153.XX
Sep 18 06:55:21 testvps wordpress(example.com)[11860]: Authentication failure for admin from 41.68.153.XX
Sep 18 06:55:46 testvps wordpress(example.com)[11861]: Authentication failure for example.com from 2.50.40.XX
Sep 18 06:56:13 testvps wordpress(example.com)[11864]: Authentication failure for Administrator from 177.138.120.XX
Sep 18 06:56:55 testvps wordpress(example.com)[11871]: Authentication failure for admin from 218.19.118.XX
Sep 18 06:56:55 testvps wordpress(example.com)[11872]: Authentication failure for admin from 218.19.118.XX
Sep 18 06:58:36 testvps wordpress(example.com)[11886]: Authentication failure for Administrator from 121.96.42.XX
Sep 18 06:59:37 testvps wordpress(example.com)[11897]: Authentication failure for Administrator from 125.22.195.XX
Sep 18 07:00:18 testvps wordpress(example.com)[11913]: Authentication failure for admin from 151.240.180.XX
Sep 18 07:00:42 testvps wordpress(example.com)[11914]: Authentication failure for admin from 41.233.195.XX
Sep 18 07:00:52 testvps wordpress(example.com)[11915]: Authentication failure for admin from 2.50.40.XX
Sep 18 07:01:23 testvps wordpress(example.com)[11916]: Authentication failure for admin from 91.121.86.XX
Sep 18 07:01:31 testvps wordpress(example.com)[11918]: Authentication failure for admin from 203.195.184.XX
Sep 18 07:03:10 testvps wordpress(example.com)[11919]: Authentication failure for Administrator from 176.121.227.XX
Sep 18 07:03:23 testvps wordpress(example.com)[11927]: Authentication failure for Administrator from 41.68.153.XX
Sep 18 07:03:26 testvps wordpress(example.com)[11934]: Authentication failure for Administrator from 109.74.73.XX
Sep 18 07:05:15 testvps wordpress(example.com)[11956]: Authentication failure for Administrator from 79.12.237.XX
Sep 18 07:05:35 testvps wordpress(example.com)[11958]: Authentication failure for Administrator from 2.50.40.XX
Sep 18 07:08:37 testvps wordpress(example.com)[11973]: Authentication failure for example.com from 201.68.2.XX
Sep 18 07:09:03 testvps wordpress(example.com)[11982]: Authentication failure for Administrator from 41.35.26.XX
Sep 18 07:09:12 testvps wordpress(example.com)[11989]: Authentication failure for Administrator from 151.240.180.XX
Sep 18 07:09:21 testvps wordpress(example.com)[11997]: Authentication failure for example.com from 205.144.215.XX
Sep 18 07:09:21 testvps wordpress(example.com)[11996]: Authentication failure for example.com from 205.144.215.XX
Sep 18 07:10:21 testvps wordpress(example.com)[12007]: Authentication failure for example.com from 113.161.230.XX
Sep 18 07:13:43 testvps wordpress(example.com)[12013]: Authentication failure for admin from 205.144.215.XX
Sep 18 07:14:36 testvps wordpress(example.com)[12023]: Authentication failure for example.com from 98.166.154.XX
Sep 18 07:16:48 testvps wordpress(example.com)[12035]: Authentication failure for example.com from 200.36.176.XX
Sep 18 07:18:00 testvps wordpress(example.com)[12039]: Authentication failure for admin from 98.166.154.XX
Sep 18 07:18:20 testvps wordpress(example.com)[12041]: Authentication failure for example.com from 200.36.176.XX
Sep 18 07:19:07 testvps wordpress(example.com)[12044]: Authentication failure for example.com from 27.54.168.XX
Sep 18 07:19:07 testvps wordpress(example.com)[12043]: Authentication failure for example.com from 201.127.74.XX
Sep 18 07:21:04 testvps wordpress(example.com)[12056]: Authentication failure for Administrator from 98.166.154.XX
Sep 18 07:23:13 testvps wordpress(example.com)[12067]: Authentication failure for example.com from 201.92.48.XX
Sep 18 07:23:49 testvps wordpress(example.com)[12069]: Authentication failure for admin from 201.127.74.XX
Sep 18 07:25:27 testvps wordpress(example.com)[12080]: Authentication failure for admin from 27.54.168.XX
Sep 18 07:25:36 testvps wordpress(example.com)[12081]: Authentication failure for admin from 113.161.230.XX
Sep 18 07:27:59 testvps wordpress(example.com)[12087]: Authentication failure for Administrator from 201.127.74.XX
Sep 18 07:29:25 testvps wordpress(example.com)[12102]: Authentication failure for example.com from 124.123.194.XX
Sep 18 07:31:24 testvps wordpress(example.com)[12121]: Authentication failure for example.com from 78.177.148.XX
Sep 18 07:31:45 testvps wordpress(example.com)[12124]: Authentication failure for Administrator from 27.54.168.XX
Sep 18 07:32:04 testvps wordpress(example.com)[12131]: Authentication failure for example.com from 108.211.163.XX
Sep 18 07:32:04 testvps wordpress(example.com)[12132]: Authentication failure for example.com from 108.211.163.XX
Sep 18 07:36:18 testvps wordpress(example.com)[12153]: Authentication failure for example.com from 142.177.17.XX
Sep 18 07:36:20 testvps wordpress(example.com)[12155]: Authentication failure for admin from 78.177.148.XX
Sep 18 07:36:38 testvps wordpress(example.com)[12156]: Authentication failure for example.com from 85.49.21.XX
Sep 18 07:36:56 testvps wordpress(example.com)[12157]: Authentication failure for admin from 108.211.163.XX
Sep 18 07:36:56 testvps wordpress(example.com)[12158]: Authentication failure for admin from 108.211.163.XX
Sep 18 07:37:36 testvps wordpress(example.com)[12167]: Authentication failure for example.com from 148.251.16.XX

 

The really scary thing about this is that owners of many WordPress blogs will probably never know that these attempts are taking place. Unless you have some sort of logging (like in the above example), the vast majority of these attempts will happen without you noticing. There may be no effect on your site at all, although if the logins are very frequent it may cause your site's performance to suffer.

 

But remember: attackers (basically) have unlimited time and resources to continue these attempts. If they finally get the password right, your site has been hacked, and is now compromised.

 

How do you tell if your site has been compromised?


Many of these attacks are trying to add your site into a network that serves spam pages trying to sell CH3AP PH4RMACEUT1CALS, or to make it so you serve malware to users. Or they might simply get added to a botnet that tries to find more vulnerable sites.

 

In the case of spamming or malware, unless you keep a really close eye on the contents of every part of your site and the log files, it's often pretty hard to notice. The first you'll hear about it will probably be something like an email from your site host saying your site is doing weird stuff. Your customers might tell you that they get a warning in Firefox or Chrome when they visit your site (like in the below images).

 

Chrome Warning Firefox Warning

 

The worst case scenario is if you have a big site with a lot of interesting data - names, email addresses, phone numbers, payment information - anything that real criminals can use for identity theft or for other scary purposes.

 

Unfortunately, in this case, if your site contains data that is more valuable than the opportunity presented by simply using it to serve spam, it might be very hard to ever notice that it's been compromised. A clever malicious user might simply choose to just sit behind the scenes in your website taking advantage of the information that they now have access to. (This is probably a pretty low risk scenario for most users.)

 

What happens if I've been hacked?

 

This is a big topic and it is dependent on precise details. There are two basic things that I'd recommend doing:


  1. Find out how the hack occurred. Was it a brute force? Was it a vulnerable plugin? If you don't know how it happened, stopping it from happening again can be very difficult. Unfortunately, finding how it happened can be difficult - you'll need to end up spending a lot of time poring over log files looking for clues.

  2. Reinstall WordPress from scratch. This is painful. You need to import your old database - but first you need to make sure there's nothing in the database that might lead to another compromise (e.g., an attacker may add themselves their own user account, which you might not notice if you have a lot of different users).

 

You can reinstall WordPress from a "last known good" backup - but you need to really know that it's good (i.e., not already compromised), and you really need to have closed whatever hole that let them in.

 

What can I do to lower the risks?

 

Here are some simple things you can do to help maximise WordPress security. Before we get into it though, two important notes:


  1. Software, and thus security of software, is a moving target. Things are changing all the time - software is modified creating new exploits, more research is done on old code revealing new weaknesses. There is no silver bullet.

  2. Prevention is better than the cure. There is always a strong temptation to postpone security measures. Don't. Do what you can right from the start.


The easy stuff:


  1. Keep the WordPress core up-to-date
    While very few vulnerabilities have been found in WordPress core recently, it is still very important to ensure you're running the latest release. This has been somewhat simplified by a recent change that offers automatic updating, but the onus is on you to keep it updated. If you're not logging into your administration section regularly (weekly at the very least), the WordPress Development Blog is a great way to stay up-to-date via RSS, or if you prefer email notifications they also have an announcement mailing list.

  2. Keep your plugins and themes up-to-date.
    Plugins are updated regularly, but they won't auto-update in WordPress. Many attackers are out there looking for holes in WordPress plugins, so it's vitally important that these are kept as current as possible.

  3. Use as few plugins as possible.
    Reduce the attack surface as much as you can. Use plugins that have high ratings. If you can, read the plugin source code to see what it does. Look for plugins that just do the one thing you need - the larger and more complex the plugin, the bigger the attack surface, and the more risk associated.

  4. Use strong passwords on your WordPress accounts.
    Come up with a strong password that is long and has a lot of funny characters. Use your browser's password system to remember it. Get another password management system like PasswordSafe and start using it to create and store strong passwords.

  5. Use strong passwords on your FTP accounts.
    FTP brute force attempts are also pretty common. If you can, disable FTP altogether.

  6. Sign up for Google Webmaster Tools.
    Google's Webmaster Tools has a bunch of great features that give you interesting insights into how your site is working. One of these tools is a malware scanner, and it will notify you if they detect anything scary on your site.

 

Harder stuff:


  1. Add a separate .htaccess-based password on your /wp-admin directory.
    If an attacker gets into your /wp-admin directory, they can basically do anything - edit your site, look at your users, read your database. Putting an additional layer of security by password protecting this directory via a .htaccess will significantly cut down risk. Setting this up only takes a few minutes, and in most cases you'll be able to save the password in your browser, so it will barely be an inconvenience.

  2. Remove write permissions.
    As noted in WordPress's own " Hardening WordPress" guide, many of the neat features in WordPress exist because it can write to the disk, allowing you to easily install plugins and themes with a single click. Unfortunately this is a massive attack vector and probably the most commonly exploited part of WordPress as a whole - one bug in the wrong spot and a malicious user can spray whatever files they want all over your site.

    In many cases, disabling write permissions will flat-out stop this from happening - in the event of an exploit in a plugin or theme, the web server will simply be unable to write to the disk, which will stop many common attacks.

    This is a tricky one though, as it comes with a big downside: it will stop a lot of WordPress functionality from working. You won't be able to install plugins and themes from the administration interface. You won't be able to update WordPress. Some plugins that need to write to the disk (e.g., WP Super Cache) might not be able to function. You won't be able to upload images.

    In short, anything that needs to write to the disk won't be able to. The site will generally operate fine though - as long as your code doesn't need to write to the disk, users will still be able to access everything and make comments and place orders and all of that stuff.

    You can, of course, simply change the permissions back if you need to do any of these things. But with the loss of convenience comes improved security.

 

For VPS users:

 

If you're running your WordPress setup on your own VPS (as opposed to shared hosting), there's a few more things you can do to reduce your risk:

 

  1. Install Fail2ban. Now!
    Fail2ban is a neat piece of software that can scan log files and perform actions based on things it sees. One very useful practical application of this is that you can catch failed login attempts to your WordPress site and then ban the IP addresses involved - massively reducing the effectiveness of brute force attacks.

    Fail2ban is good to have on your VPS in general (it can stop other kinds of brute force attempts, including SSH and FTP). It takes a few minutes to install and set up by itself, and there's already a good WordPress plugin called WP fail2ban that is dead easy to get working.

    As a bonus, in addition to increasing security it's possible you'll see some performance improvements as well as large-volume brute forces are cut off early and stop hammering your site.

  2. Install Tripwire.
    Tripwire monitors changes to files on your disk. It's a useful security tool for WordPress - you can check to see if any of your files have been edited, or if new files have been added, without you doing something.

    It's a little more fiddly, but there are plenty of guides online that can walk you through the process.

 

WordPress is no longer just a great platform for blogging - it's a flexible piece of software that can be used as the basis for many projects. When handled with care it can be just as reliable and secure as anything else, but it's vitally important to remember that - as with any popular software that is Internet-connected - it will be a target for hackers.



Post a comment

Preload Preload Preload