The Definitive Guide to WordPress Security
The author's views are entirely their own (excluding the unlikely event of hypnosis) and may not always reflect the views of Moz.
If you work in online marketing, the chances are good that you've worked on, are working on, or will at some point work on a WordPress site. If you work with wordpress.org in any capacity, this post is for you (much of this post doesn't apply to *.wordpress.com hosted sites).
Script kiddies suck
In hacker lingo, a script kiddie is the lowliest form of hacker (using the term hacker loosely), and relies on common tools and scripts to find and take advantage of the weakest and most common security vulnerabilities: crappy passwords, use of public WiFi without a VPN, outdated plugins, low-security hosting, phishing attacks, and other things of this nature. Sadly, these issues alone grant access to a shocking number of sites.
Unless you're in charge of a WordPress site for a major brand, the majority of the security issues you're likely to face will be the result of script kiddies.
The good news is this: If you follow this guide, your site should be as close to invulnerable as you can reasonably get. (To be fair, nothing is truly invulnerable, but this will get you pretty close.) Abracadabra, vault-like security is yours.
Without further ado, let's dive in. I personally take a four-tiered approach to WordPress security:
Hosting and server level security
When it comes to securing WordPress, it's best to start from the ground up. When you host your website with a hosting company that isn't sufficiently security-conscious, if any site on a server is hacked, there's a chance that any other site on that same server could be vulnerable.
After a ton of research, I've determined that the most secure option for hosting Wordpress is WPEngine.com (and, conveniently, Moz has a PRO perk for them, 4 months of free hosting).
The effort they put into security is re-freaking-diculous (seriously). I'm in the process of moving all of my WordPress sites over to them as we speak. They aren't cheap, but you get quite a lot for what you pay. They even have a partnership with Sucuri Security, so if your site ever gets hacked, they'll fix it for free.
That said, they might not be a perfect fit for everyone. For example, there are quite a few plugins they don't allow (many for performance issues, not security issues). There are alternates to most plugins though, so hopefully that isn't a deal breaker.
If you HAVE to use another host for whatever reason, or need to host on your own servers, there are a few things to keep in mind (WP Engine does most, if not all, of this):
- Run secure, stable versions of your web server and any software on that server.
- Have a server-level firewall.
- Keep your server under lock and key. Only your IT team should have access.
- Never, ever access your server from an unsecure network.
- If you need to FTP in, use SFTP via a reputable program (I like FileZilla).
- Make sure your MySQL installation is as secure as possible.
- Always create a unique database for each blog installation, and make sure your database table DOES NOT begin with wp_.
- Backup your database and other files as often as possible, especially right before you make a change (there are plenty of options for this, such as CodeGuard and VaultPress).
- And, of course, make sure your passwords are both complex and not used elsewhere.
There's more to this, but those are the biggies. If you want a lot more detail, go here and here.
The next step in this process involves configuring some server rules. If you have access to the main server configuration file, it's best to do these things at that level, but not everyone is going to have that access. For that reason, I'm going to cover how to do this via the .htaccess file by walking you through a real .htaccess file (Note: edit your .htaccess file AFTER you install WP. It's server-centric though, so I'm covering it here).
BIG FAT WARNING: Be very, very careful when making changes to your .htaccess file. If you aren't extremely comfortable with code, it's best to let your developer do this. I've personally used all of this code, exactly as is, but I've seen bits work on some sites and break things on others (it totally depends on your server configuration, plugins installed, etc.). To be safe, get your developer to do this for you.
WordPress auto-creates a section in the .htaccess file. Don't put anything inside of the WordPress section of the .htaccess, as it will be overwritten. Some things will need to go before the WordPress .htaccess section, and some things after, to avoid breaking things. If you don't know what should go where, you probably shouldn't be editing your .htaccess file.
OK, here goes...
This first bit of code helps to prevent errors on some Apache servers, and activates the rewrite engine (which many of these commands require to function):
## Include this at the start of your .htaccess file ## Options +FollowSymlinks RewriteEngine On
This next bit turns off the server signature. This is a "security by obscurity" trick, as the less info a hacker has about your system, the harder it is to get in. The more they know, the easier it is to go out and hunt for known exploits:
## Disable the Server Signature ## ServerSignature Off
Sometimes spammers will append their own crappy query strings to the end of a URL, attempting to do all kinds of nasty things, and this next bit of code can negate it by 301 redirecting certain query strings back to the canonical URL.
Just edit the enter|query|strings|here bit to include the query strings you're having issues with, separated by pipes (a pipe is a separator in RegEx). This next bit of code also has uses beyond blocking spammers, and can sort out issues with ?replytocom and other common junk query strings:
## Remove Spammy Query Strings ## <ifModule mod_rewrite.c> RewriteCond %{QUERY_STRING} enter|separated|query|strings|here [NC] RewriteRule .* http://www.%{HTTP_HOST}/$1? [R=301,L] </ifModule>
While not hacker-specific (though it certainly could be), this next bit of code will prevent bots with no user agent from hitting your site. Just change out yourwebsite.com with your actual URL before placing this in your .htaccess:
## Protect from spam bots ## <IfModule mod_rewrite.c> RewriteCond %{REQUEST_METHOD} POST RewriteCond %{REQUEST_URI} .wp-comments-post\.php* RewriteCond %{HTTP_REFERER} !.yourwebsite.com.* [OR] RewriteCond %{HTTP_USER_AGENT} ^$ RewriteRule (.*) ^http://%{REMOTE_ADDR}/$ [R=301,L] </IfModule>
A common hacking tactic is a SQL injection, and this bit of code can block the vast majority of attempts:
## SQL Injection Block ## <IfModule mod_rewrite.c> RewriteBase / RewriteCond %{REQUEST_METHOD} ^(HEAD|TRACE|DELETE|TRACK) [NC] RewriteRule ^(.*)$ - [F,L] RewriteCond %{QUERY_STRING} \.\.\/ [NC,OR] RewriteCond %{QUERY_STRING} boot\.ini [NC,OR] RewriteCond %{QUERY_STRING} tag\= [NC,OR] RewriteCond %{QUERY_STRING} ftp\: [NC,OR] RewriteCond %{QUERY_STRING} http\: [NC,OR] RewriteCond %{QUERY_STRING} https\: [NC,OR] RewriteCond %{QUERY_STRING} (\|%3E) [NC,OR] RewriteCond %{QUERY_STRING} mosConfig_[a-zA-Z_]{1,21}(=|%3D) [NC,OR] RewriteCond %{QUERY_STRING} base64_encode.*\(.*\) [NC,OR] RewriteCond %{QUERY_STRING} ^.*(\[|\]|\(|\)||ê|"|;|\?|\*|=$).* [NC,OR] RewriteCond %{QUERY_STRING} ^.*("|'|<|>|\|{||).* [NC,OR] RewriteCond %{QUERY_STRING} ^.*(%24&x).* [NC,OR] RewriteCond %{QUERY_STRING} ^.*(%0|%A|%B|%C|%D|%E|%F|127\.0).* [NC,OR] RewriteCond %{QUERY_STRING} ^.*(globals|encode|localhost|loopback).* [NC,OR] RewriteCond %{QUERY_STRING} ^.*(request|select|insert|union|declare).* [NC] RewriteCond %{HTTP_COOKIE} !^.*wordpress_logged_in_.*$ RewriteRule ^(.*)$ - [F,L] </IfModule>
Now, there are plugins that can limit the number of login attempts from any one IP address, but that doesn't prevent hackers from using large blocks of IPs to brute-force your site (a la public proxy lists). I've experienced this first hand numerous times, so the following bit of code has been a lifesaver as it only allows my login pages to be reached from IP addresses I specify, and blocks access to those pages from all other IPs.
Just adjust the allow from lines to reflect your actual IP addresses (you can get your IP addresses by going to Google from each place you connect to the internet and searching "What is my IP"). If needed, change the login filenames as well (wp-login.php is default, and login is not, but my site uses both because of a plugin I use).
Or, to make it easier on yourself, go to ProxyBonanza and pay $10/mo for one exclusive proxy IP of your own, and then allow that IP and use that IP whenever you want to access your sites. (ProxyBonanza has plugins for Firefox and Chrome, which make this step really easy.) Just swap out the fake IPs below with your actual IPs. If your IP changes, you can always go in and fix this via FTP later.
## Restrict WordPress Login Pages to Your Own IPs ## <Files wp-login.php> order deny,allow deny from all allow from 192.168.1.1 allow from 192.168.1.2 </Files> <Files login> order deny,allow deny from all allow from 192.168.1.1 allow from 192.168.1.1 </Files>
There are a number of files that nobody but you should ever be accessing, and this bit of code will block them from being accessed via a browser:
## Block Sensitive Files ## Options All -Indexes <files .htaccess> Order allow,deny Deny from all </files> <files readme.html> Order allow,deny Deny from all </files> <files license.txt> Order allow,deny Deny from all </files> <files install.php> Order allow,deny Deny from all </files> <files wp-config.php> Order allow,deny Deny from all </files> <files error_log> Order allow,deny Deny from all </files> <files fantastico_fileslist.txt> Order allow,deny Deny from all </files> <files fantversion.php> Order allow,deny Deny from all </files>
If you find your site being hit repeatedly with attack attempts from certain IP addresses, you can manually block certain IPs with the following bit of code. Just edit the deny from bit to include the offending IP, with one IP per line as follows:
## Malicious IP Blocking ## order allow,deny deny from 1.1.1.1 deny from 2.2.2.2 allow from all
If you have people hitting you really often from the same IP or IP block, you can redirect that IP/IP block to a nice rickroll video (just change the IP below to reflect the one that's hitting you). :) I've done this on my sites for a few repeat offenders:
## Redirect Recurring Spammer IPs to a Rickroll Video ## RewriteCond %{REMOTE_ADDR} ^192\.168\.1\.1$ RewriteRule .* http://www.youtube.com/watch?v=oHg5SJYRHA0 [R=302,L]
If you have certain websites that are hitting you with referral traffic you don't want (it can happen for various reasons), you can block those referring domains with this code:
## Block Certain Referring Domains ## RewriteCond %{HTTP_REFERER} digg\.com [NC] RewriteRule .* – [F]
You can also use your .htaccess file to secure wp-includes (this can cause real issues, especially with Multisite, so I'll have you go here for the specifics). You can also do some other pretty advanced things, like blocking certain countries and browser languages, if you so choose.
With all of that in place, your .htaccess file is just about as hardened as it can get. An .htaccess file can exist for each directory on a site, and is applied to everything in and under that directory. I've compiled this list from a number of different articles, with a few bits of my own sprinkled in. For further reading on these and other similar points, check out these five links.
The last step is to lock down your file permissions so that only those who should have access to certain files have that access. You can read how to change file permissions here (be careful with this one too, as it can break things, particularly plugins.) This is something you should test very carefully as you implement it, ideally in a sandbox or dev environment.
And that's it for WordPress server-level security (not really — you could fill a book with this stuff — but this should be sufficient for your needs). Next up, WordPress itself!
Your WordPress installation
Once you have your hosting and server security sorted out, it's time to get WordPress installed, along with the necessary security plugins. Even if you already have an existing WordPress site, don't skip this section!
You'll want to download the WordPress install files directly from wordpress.org, and go through the install process via secure FTP (SFTP). Many hosts offer a one-touch WP install, which is also fine. As you do this, make sure you pick secure passwords (outlined in the next section), and don't use the same password for more than one site/thing (separate passwords for your database, FTP, WordPress admin, etc.)
With WordPress installed, the next step will be to pick a theme — and not just any theme will do. As any black-hat SEO knows, themes and plugins have long been a great way to get links, albeit in a shady and unethical way (remember MozCon 2011, when Richard Baxter gave a live demonstration of pointing millions of links with anchor text of his choice from a set of WordPress sites running a theme/plugin he'd created? Yeah.)
Because a lot of potentially dangerous things can be hidden inside of themes, it's a good idea to use or buy a secure, clean theme. The themes that come with wordpress.org by default are pretty safe, but here are a few other options for clean themes: Option 1 and Option 2. To get a better feel for why this is so important, there's a great video here.
If you already have a theme installed, you might want to run a security scan, or have a security-minded developer look through the theme code. Ditto for any plugins you might have.
After you've selected your theme, the next step is to start picking plugins. When it comes to plugins, you need to be just as careful as you were with picking a theme. Even popular plugins can contain vulnerabilities, and developers can sometimes be slow to fix them (or perhaps put them there themselves). For that reason, I recommend using as few plugins as possible to get the job done. That said, from a security perspective, here are the plugins I highly recommend:
- Better WP Security - This is sort of an all-in-one security option. It handles a variety of tactics covered in this post. Can overlap with other plugins, so be careful. Free.
- Limit Login Attempts - Exactly what it says, and a phenomenal way to deter brute-force hacking attempts on a site. Free.
- Akismet - Great way to filter out a lot of crap before it ever touches your site. If your site is easy to spam, it might also be easy to hack, so make it a hardened target on all fronts. Paid.
- Sucuri Security - When you pay for this service, you get a plugin to install on your site that helps with the monitoring and hardening process. It has overlap with other plugins though, such as Limit Login Attempts and Better WP Security, so you don't want to use all of them at once. Paid.
- CodeGuard - Great backup service that lets you easily roll back if you ever do get hacked. Also, people don't back things up nearly as often as they should, so doing it automatically is handy. Paid.
- CloudFlare - CloudFlare is a CDN, but also so much more. It has some great security features built in, and comes in both free and paid versions.
- Google Authenticator - Enables two-factor authentication on WordPress, which is awesome. I use two-factor wherever it's offered, because it rocks. Free.
- Stealth Login Page - You can't crack what you can't find. This plugin hides your login page without needing to edit .htaccess files. Free.
- WordPress SEO by Yoast - Not only does this have great SEO benefits, but it allows you to easily edit your .htaccess file from within the WordPress admin, which is very handy. Free.
If you opt to use WP-Engine for your hosting, be aware that they are very strict on what plugins they do and don't permit. I find this pretty annoying, and while I understand their reasons, I really like some of the plugins they don't permit.
If you have unused themes or plugins installed, I'd recommend deleting them. Just having them installed on your site, even if they aren't active, can potentially pose problems. You should also make sure that you keep WordPress, your plugins and your themes up-to-date. Updates often fix known security issues, and one of the first things a smart hacker looks for is out-of-date plugins and themes they can exploit.
As you build out your site, you should also pay very close attention to what is and isn't reachable by crawlers, and how your site handles things like login info, passwords, lost passwords/password resets, security questions, etc. There's an entire sub-set of hacking called Google hacking, dedicated to surfacing information Google has found and indexed that it probably shouldn't have (great article here). Making effective use of your robots.txt file to block things that should be blocked is highly recommended.
While site security is never finished, this will sort out the vast majority of problems you're likely to encounter. Remember, nothing is unhackable, so the goal is simply to make your site more way trouble than it's worth to the majority of hackers.
Personal security
As any half-decent hacker knows, the human element of security is usually the weakest link in the chain. The most security-conscious web admin or host can be foiled by a common password (Love, Sex, Secret, God, Hack the Planet!).
The human brain likes routines, patterns, and comfort zones; and hackers exploit that with glee! If you want a fascinating yet frightening read on this topic, check out Kevin Mitnick's book The Art of Deception.
Here are my seven personal best practices for locking down the human element:
- Never access a WiFi hotspot through anything other than a secure VPN. I personally use Cloak as my VPN (iOS and Mac only at this point), but there are lots of options. You'd be shocked at what can be found with simple packet sniffing (Firesheep is a great example, and will probably make you quite uncomfortable). When you use a WiFi network, secured or unsecured, anyone else on that network can get access to your traffic (if all your traffic is encrypted, you're MUCH safer, which is why you should use a secure VPN on any shared network, even if it's a "secure" shared network). If you have WiFi at home or work, make the password a strong one, use WPA2, and set your router to NOT display the SSID (this is a "security by obscurity" tactic).
- Get a firewall. A good firewall is an excellent defensive tool. In a perfect world, I'd recommend having both a software and a hardware firewall, but that may not be feasible for everyone. At the very least, you need a software firewall (Comodo, ZoneAlarm, etc.). It can be a bit intrusive, depending on your settings, but it's easy to customize and does a very good job. You should have a firewall on every desktop/laptop/server.
- Get an antivirus program. Viruses and malware are a dime a dozen, and the chances are REALLY good that you've got at least one on your machine already. If a hacker has access to your computer, no amount of security anywhere else can protect your WordPress installation (not to mention your email, bank account, etc.) I've tried quite a few over the years, and I'm partial to Avast. It's one of the least resource-intensive AV programs on the market (won't bog down your machine), but it's also extremely thorough (there's a free version, but I pay for the full suite for a variety of reasons).
- Keep your hardware physically secure. If someone can get to your machine, it's a cinch to hook up a keylogger. If you don't password protect your machine, there are all kinds of other quick and dirty things they could do as well. If you use a desktop in particular, and it's in a common area at work, periodically check your USB ports and all cords running into the machine for anything unusual. It's uncommon, but it happens. Seriously, you should see the type of security Google has at its server farms!
- Use really good passwords, and don't ever reuse passwords on multiple sites. Here's where the lazy human element really comes into play. We're not really good at remembering obscure passwords, so we tend to stick with things we'll remember (asdf, 12345678, qwerty12345, etc.). This is bad, because common passwords make things REALLY easy for hackers, especially if you use the same password for multiple sites (don't do that, ever).
Operating system passwords are notoriously easy to crack with rainbow tables, so make sure your OS password is long (at least 15 characters) and complex (uppercase and lowercase letters, numbers and symbols, avoiding common substitutions like @ for A or 8 for B, etc.). Here's a cool article that explains why complex passwords make things SO much harder for hackers.
Thanks to some pretty serious security blunders over the years, it's easy to find massive lists of passwords used on pretty major sites (RockYou is a great example, with 32 million passwords leaked). With a list like that, you can just pick a WordPress site and try random passwords at will until you get a hit. While far from efficient, script kiddies in particular love this brute-force approach.
I've found the easiest way to have virtually unbreakable passwords is to use a tool like LastPass, 1Password or Roboform. They allow you to generate a random, long, extremely complex password for each site, and then encrypt and store them all with one master password. There are desktop and mobile apps available (some of which even contain a secure browsing environment), so you can easily login from your various devices, and all you have to remember is one password to access them all (for the love of all that is holy, at least make that one password complex).
Don't write down, print, or store your passwords in plain text on your computer. Just don't. - Protect your email accounts with two-factor authentication (and then protect your phone too). If a hacker can't get into your site via the password, their next trick is usually trying to crack your email account so they can just do a reset. If your email provider offers two-factor authentication, USE IT.
If you do this, make sure you lock your phone (use a real password, not the 4 digit variety) and try really hard not to lose it, since that is now the key to your accounts (and, in a perfect world, don't put that phone number up online, just to be safe. If a website ever needs a phone number, get a Google Voice number that you use just for that.) You should probably also set your phone to wipe after a certain number of failed tries, and configure a remote wipe option as well, if possible, as your phone is now the key to your accounts.
If your account provider asks you for security questions, use a mnemonic to come up with a totally separate answer (for example: for the question "What was your high school mascot?", I might think, I really hated my CS teacher in high school, and then use that teacher's name as the answer.) This will effectively neutralize attempts to mine your social profiles for data hackers can use to guess your security questions. - Learn to recognize and avoid phishing attacks. Whether by email or website, phishing attacks are one of the most common causes of security breaches (you might have heard about the hacked AP Twitter account fiasco that caused a massive stock drop — yeah, that was due to a phishing attack).
When it comes to avoiding these sorts of attacks, I live by three rules:
If I have to log in to a site, I only navigate to that site through my password manager (this prevents me from accidentally falling for a misspelling URL phishing attack, like if I were to type Facebool.com instead of Facebook.com).
Never, ever click on a link in an email and then login to whatever page pops up (see last rule). In fact, I don't click on links in email anymore. I right-click, copy link location, and then paste it into Google, just to be safe. If it doesn't look right, or the results include spammy stuff, I stop there.
Never, ever open an attachment from someone you don't know and trust (and even if you know and trust them, drop it in a folder and run a virus check on it before opening it, or open it in a sandbox program first just to be safe). If someone who has you in their contact list gets their email hacked, the hackers start by blasting out emails to that person's contact list to expand their phishing pond.
Last but not least, exercise constant diligence
When it comes to WordPress security, you can't just set it and forget it.
If you put all of this in place, and then fail to monitor and update and change things as time goes by, you'll be in just as bad of shape as if you'd never done any of this to begin with.
To make sure that all of your hard work doesn't go to waste, I recommend a seven-step checklist to maintain constant vigilance for your WordPress sites:
- Keep WordPress updated. I'm in my sites daily, so I keep an eye on this daily. WordPress doesn't update the core too terribly often, so I'd recommend checking this at least monthly to be safe. You might want to have your dev team do this, as updates sometimes break things.
- Keep your plugins updated. Plugins are one of the most vulnerable parts of WordPress, not only to external hackers, but to malicious or greedy programmers. While we already covered only using reputable plugins, also make sure you keep these plugins updated, just in case a vulnerability is being addressed in the update. Again, you might want to have your dev team do this, as updates can sometimes break things.
- Monitor your server log files. This might be overkill for most folks, unless you've spotted something suspicious. Your server logs will give you the details of everything that has hit your site, human or bot, and when and from what IP address. You can find some awesome stuff in here, so keep an eye on it from time to time. (AWStats is a good free tool for this.)
- Monitor WP access. You can use a plugin like Simple Login Log to monitor the details of logins to your site. DO THIS.
- Monitor for file changes. A plugin like CodeGuard will send you emails whenever your WordPress files are changed. This can be an early-warning system for a hack, and is worth the investment. It also allows you to roll back changes if needed.
- Change your password periodically. I'd recommend every 3-6 months, but once per year is probably sufficient if you're using a sufficiently complex and unique password.
- Keep Your Firewall and Antivirus Software Updated - New threats are discovered constantly, so it's important to keep everything updated. Out-of-date security software is a vulnerability.
Comments
Please keep your comments TAGFEE by following the community etiquette
Comments are closed. Got a burning question? Head to our Q&A section to start a new conversation.