WordPress powers more than a third of all websites and is a popular target for hackers. Hackers start scanning and probing for vulnerabilities within minutes of a new website going online. It is essential that your websites be protected. The first thing I do when after installing WordPress is install a security plugin. With a good security plugin in place, I feel comfortable taking time to setup and configure the new site.
This article is for people serious about their website security and who are interested in figuring out what needs to be done to secure a WordPress site. This is my list of what needs protection and why. With this information can we evaluate security options to see if our “stack” is covering all the bases.
In the past, I tried to get a handle on WordPress security by looking for a good plugin. If the plugin was widely recommended then that must be a good solution. When I looked into the different plugin features I found that some features were missing from my go-to and so installed two plugins, but without a clear notion of if the “security problem” was solved. I was going about it backwards.
Before we can evaluate security solutions, we need to understand what we are trying to protect. This seems very logical in hindsight. With your home, you can see the windows and doors. For most users, what they “see” of their website is the front-end and the admin side. So, securing access to the admin side of the site makes sense, and may seem enough. While this is important, there is more that needs attention.
Why is WordPress Security So Confusing?
I’ve been using security plugins for years, but I’ve only been focusing on it for the past year. My conclusion is that WordPress security is what it is for a few reasons:
The result of this is that there are a lot of competing solutions. Where there is overlap, each one does it differently. They may be effective in some areas, but not all. Some have a light touch while others bring servers to their knees. You get the idea. Also, it is easy to find authoritative articles that are now out of date. People still repeat truisms and turn to solutions from the past, but things have changed. Yes, WordPress security is confusing. So, let’s sort it out.
WordPress Security Setup
There is a continuum from no security in place at all, to locked down to the point of being unusable. I think there is a middle ground that is a minimum reasonable requirement, that constitutes best practices, and after that there are choices. I’m interested in identifying the steps that can be considered best practices.
So there are some things on this list that I’m considering “essential.” I imagine those designations might be different for different people. At the end of the article there is a checklist where I have marked tasks as required, situational, or optional. You can download a copy of the list for yourself.
I’m targeting the list and discussion to be applicable for most WordPress sites. There is a section near the end for “situational overrides” where I mention cases that I know of that might require extra steps. Another variable is the site owner’s tolerance for a breach. No one wants to be hacked, but for some sites being hacked may mean a large financial or reputation loss. In these cases, extra security steps are also warranted. Also, if you run your own server, or virtual machine, more responsibility for updates and security falls on you and this guide does not address that type of situation.
When Selecting Hosting
Servers are regularly updated: Servers receive regular updates just like your personal computer. We rely on the hosting provider to keep the server software up to date and patched. Clients often have no insight into these matters, so we must choose a reputable hosting provider for them.
PHP and Database versions kept current: It is important that the hosting provider offers current versions of PHP and MySQL (or MariaDB). It is a good idea to not fall behind, so check the required and supported version lists from WordPress.org.
Containerized sites or control site security policy on shared hosting: Sites on shared hosting are potentially susceptible to compromise though path traversal. The situation here is that on the file system level an attacker who compromises one site can access the files of another site and infect them. Poorly configured servers might allow this between separate accounts, but this can also be the case when people can install multiple sites under one account. If they are all your sites or you are the administrator for all of those sites, then this might be an acceptable risk, but sometimes a developer or freelancer will host several people’s sites under one account. Persons A, B, and C may be very careful, but Person D is not, and everyone’s sites get hacked. Higher-end hosting uses “containers” and allow only one site per container. Best practice: one site per container or have firm control over security on shared hosting.
Select hosting with free SSL certificate (optional): By default, web pages are served over clear text. The potential problem with this is that form submissions are also transmitted in a clear and easy to read format. Using page encryption over HTTPS, (sometimes referred to as SSL, though things have changed), the web page contents are protected (but not the URL) from middlemen. Obviously, this is desirable for login forms where users are entering their usernames and passwords and legally required when users can enter credit card information. There was a time when SSL was resisted because encryption and decryption were processor intensive. However, server hardware is so much more robust these days that this is no longer an impediment. Thanks to free Let’s Encrypt SSL certificates, and pressuring from Google, most sites are SSL based. If your site has a login or accepts any sensitive information via a submit form, you need SSL. If your hosting provider offers free Let’s Encrypt SSL certificates then that can save you the cost of a separate purchase.
Site Builder Tasks When Installing WordPress
Change default admin username: Along the lines of keeping usernames private, the WordPress admin username has a default of “admin.” When you install WordPress select a username other than “admin.” If you inherited as site where admin was “admin,” there are plugins available to change this, or you can do it directly in the database.
Use strong admin password: WordPress generates strong passwords by default. Don’t override this.
Change database table prefix (optional): There are a few WordPress defaults that people often recommend you change. When you install WordPress the installation process defaults to using a database table prefix of “WP_”. The idea in changing this is that if people trying to hack your database already know the table names if you don’t. If you do change the table prefix, it makes it harder for them. My thinking is that if an intruder can already read or write to your database then you already have a problem. You have the option to change this during the install or you can use a plugin or manually do it afterwards. It doesn’t hurt to change this, but I consider this optional.
Site Builder Tasks When Setting Up Site
Use HTTPS and a valid SSL certificate: If your hosting provides free Let’s Encrypt SSL certificates then set that up after installing WordPress. Otherwise, arrange to purchase an SSL certificate and talk with your hosting provider about getting it installed.
Check that all links go over SSL: It is important to check that all traffic is flowing over the encrypted channel. Make sure the site redirects automatically to HTTPS if accessed using HTTP. Also check that there is no “mixed content” where some links on the page are using HTTPS and others HTTP. If there is mixed content the web browser will show the page as insecure and you may have some sensitive information being passed in the clear. You can check your browser and there are third party scanners available to make sure there is no mixed content.
Site Lockdown Tasks
Install and configure a WordPress firewall: All reputable hosting providers have network firewalls in place and all traffic passes through them. However, most of these are coarse-grained firewall filters. They keep out the obvious and worst intruders, but firewall issues can be difficult to recognize and require skilled ops to fix. Consequently, they err on the side of allowing through any traffic that could be legitimate … with the result that their users need a WordPress firewall (aka a Web Application Firewall or WAF).
Use a firewall that gets just-in-time rule updates: A feature of some WordPress firewalls is that they can receive just-in-time rule updates. This is the only way to be protected from newly discovered plugin and theme vulnerabilities and seems essential.
Login form protection to stop brute force login attempts is also important. Without it hacker bots can camp your login page for days, running through known password lists, trying to break in. There are two types of login protection. Network brute force protection pools information from lots of sites together. If an IP address is identified as belonging to hacker on one site, it is added to a list and other sites in the network know to ban it when it shows up. The other type of brute force protection is local, which tracks unsuccessful login attempts and blocks the IP from further submissions after a set number of failures. In addition to keeping track of failed attempts, Recaptcha or honey-pot techniques can be used to minimize repeated login attempts. At least local brute force protection is required.
Two factor authentication (2FA) is a bit of a pain, but it is a good way to secure your login. 2FA adds a third ingredient to the usual username and password login check. There are several ways of supplying the 3rd piece. Typically, people have an app on their smart phone that shares a key with your site. Using the shared key, the phone app generates a time-based value that can be confirmed as valid by the login process. I think 2FA is a good idea for all sites, but a requirement for a site with ecommerce or for admins of a membership site.
Form protection: In addition to the login form, WordPress sites also accept form submissions via contact forms and account recovery forms and these need to be protected. If other custom forms are enabled, they too should be protected. The forms need to be protected from bot submissions as well as spam submissions. Recaptcha is a popular response to thwart bot submissions. Various “honey pot” techniques can also be used. If you are getting spam submissions then there are several plugins which help to guard against that.
Setup regular backups: Backups are often considered a matter of security for good reason. If your site is compromised, and you can identify when the compromise took place, restoring an earlier backup is often part of the easiest way to “get clean.” If things get hairy, backup files can also provide a baseline for comparison, so you can research which files were infected. Most sites should be backed up daily, though “brochure sites” could be backed up weekly.
Of course, it is necessary to store the backup files off-site and not on the same server, or even the same location, as the website. This ensures that backup files are available in the event of a server crash or natural disaster. It is a good practice to test the backup process to make sure that backup files are not corrupted and can be restored.
Setup regular malware scans: What happens if our best efforts at prevention weren’t enough and our site got hacked? Without regular checks, a hack may go unnoticed for a long time, infecting visitors, hosting botnets, and ruining your reputation. Regular malware scans can alert the owner if the site has been compromised. Ideally scan daily, but no less than once a week.
Setup activity logs: If your site was hacked, when was it hacked? Was a rogue plugin installed? Activity logs can provide a history that is very useful in tracking down issues or hacks so they can be repaired. At the least, I think you need malware scanning and activity logs.
Setup up-time monitoring: Up-time monitoring performs a checked check of the site to ensure it is online. Some up-time monitors also check page contents to guard against defacement. These services alert the site administrator when there is a problem. Outages can sometimes be a sign of site takeover or of a network or server issue.
Disable XMLRPC: In addition to the regular login form, WordPress also allows login via XMLRPC. “RPC” stands for Remote Procedure Call and this type of communication uses XML over HTTP. This isn’t used much, but some services, such as JetPack, still use it. Ideally turn it off because it can be subject to brute force attacks just like the regular login form.
Prevent user enumeration: WordPress also, sadly, by default allows for user enumeration. It is easy to submit a request and get back user information for anyone who has published an article, everything except the email and password. With the introduction of the RestAPI, you can get individual user information as well as a list of users. If you don’t have two factor authentication enabled, then you just need both the username and password to login. If it is not locked down, user enumeration provides half the equation. In my opinion, user enumeration should be blocked, though the WordPress core team thinks otherwise.
Correct file and directory permissions: There is also the need to have the permissions set correctly within the web site’s home directory. This is technical and can be confusing. Should that be “644” or “755”? This is not user-friendly territory but is important. Good hosts set this correctly and there are plugins that check the directories and files permissions and fix problems. Either your host needs to attend to this, or you need a plugin that checks.
Prevent directory listing: Additionally, you want to prevent directory listing where someone can browse to the directory and the contents of the directory are listed. This can be prevented either by setting a web server directive (in the .htaccess file) or by placing an empty “index.php” file in the folder to stop it. Further, we also need to block PHP execution in un-trusted folders, such as the uploads folder. This can also be prevented by setting a web server directive.
Disable file editor and installing plugins and themes (optional): Along these lines, another step some people take is to disable the built-in file editor and disable the installation of plugins and themes. These are capabilities limited to the admin role, so this seems to me to be a bit like closing the barn door after the horse has gotten loose.
Monitor file changes (optional): A common security practice provided by some plugins is a scan for file changes. The idea is that this could alert you to a hack and infection because changed files would be listed. I can imagine this being useful for WordPress core and known themes and plugins. Practically, however, these scans often don’t account for theme and plugin updates and there are a lot of files that do change, such as backups or cache files. To make use of this type of tool you need to do a fair amount of configuration and set several exclusions to avoid false positives and make it useful.
Change login URL (optional): There are lots of bots and scanners that target the “wp-login.php” page. Some security plugins provide the ability to change the URL for the login page. There are two possible issues with this approach. First, this is an instance of “security through obscurity” in that you are trying to hide your login page. If your username and password are not secure, hiding it won’t help. You will still get hacked. Second, users sometimes forget the new login URL or 3rd party login forms may not function correctly. This can be an annoyance. Those issues aside, I imagine one reason for wanting to change the login URL is to help to cut down on churn. Bots that target the login page won’t find it and you will have fewer brute force attempts.
Hide that WordPress is being used (optional): Another “security through obscurity” technique is to hide the WordPress version, or try to hide that the site is running WordPress. I doubt the value in this as a lot of the malware attacks run through a list of possible exploits regardless of the content management system and even the programming language being used.
Block bot scanners (optional): Another common type of block is one that is based on many 404, file not found, requests. The idea is that a hacker scanning the site doesn’t know what is installed and so is running through a list of known vulnerable files looking for an entry point. Lots of 404 errors is a likely indicator of this activity. A scan for files that don’t exist won’t result in a break in, but it does cause a lot of churn, and of course you could have some vulnerable files without realizing it. There are two ways of addressing this type of attack. One is to monitor the number of 404 requests during a given time frame and block further attempts for that IP address if the threshold is reached. Another approach is to use firewall filter rules like the hacker’s and block the IP if this type of behavior is detected.
Disable obscure features (optional): WordPress can post articles using “Windows Live Writer,” which is used by almost no-one. I have no clue why this remains on by default. Similar case for the “Really Simple Discovery Header” that WordPress adds to page headers. This is supposed to make it easier for people to post to the site but is rarely used. Turning these off is a common lock down step but they are enabled on many sites without issue.
Ongoing Maintenance and Procedures
Keep site up to date: It doesn’t help us if WordPress core, our theme and plugin authors fix bugs and security holes, if we don’t install the updates. Keeping up-to-date is a vital part of the security process. It is easy to forget to check for updates, especially if maintaining websites isn’t your job. Some web hosts will apply updates for you because the last thing they want to be hosting an infected site. Also, some plugins / services notify you when a update is available.
Strong passwords are a must because it is too easy for bots to guess weak ones. WordPress has strong password enforcement on by default. Don’t turn it off. If you operate a membership site, or other site where users have a login, be sure strong password enforcement is turned on for them as well.
Check that malware scans are running: Periodically check that the scans are running and check their log files.
Periodically test the backup and restore process: People think they have a good backup, but you would be surprised at the number of times that the backup file wasn’t saved, is missing important files, or is corrupted. So it is a good idea to periodically test. When a site has been up for a while and I want to test the restore process I usually do so on a development, staging or testing site.
Change salts (optional): The WordPress “wp-config.php” file contains a list of “salts” which are randomized values used when generating hashes for cookies, saving passwords to the database, and nouces. A “hash” is a created by scrambling the password plus salt using an algorithm. When you log in, the same hash process is run and your hashed password in the database is compared with what you typed in, and a match is attempted. The value of using this process is that if someone gains access to the database, they will only see your hashed password and it would be very difficult to unscramble it. A “nouce” is a random value that includes a time value. They are generated on the fly when used, are meant to be used only once, and the time value is checked on use to help ensure that old submissions are not reused later. When you install WordPress using the installer the salts are generated on the fly and thus unique for your site. I found several articles suggesting they be regenerated a few times a year, but I don’t believe this is usually done.
Assign user roles correctly: WordPress has a user role system and each role has permissions to perform different types of tasks. The admin role is the most powerful role and should only be assigned to trusted users who need those permissions. It is important to review those roles and assign them carefully assign them to users.
Manage old user accounts: Sometimes a user is created for a developer or company to troubleshoot an issue. Other times users may leave a company or a membership site. These old user accounts can be an entry point for a hacker. Delete old admin or employee accounts that aren’t being used. If you have a subscription site where users might return then it might be impractical to remove them. In these cases make sure that these inactive accounts have only restricted permissions.
Pay attention to your websites: It is important to occasionally visit your site, login, and check that everything looks as it should. It is also a good idea to check the file system using an FTP client or other means to check for unusual files or problems. Periodically test the contact and comment forms to make sure they are working. Otherwise, if a visitor notices a problem they may not have a way to let you know.
These steps don’t apply to most websites, but they are worth mentioning as they make sense in some situations.
Avoid shared hosting: Busy sites, ecommerce sites of any but the smallest size, and high profile sites should avoid shared hosting. These types of sites won’t have the performance and security that they require.
Use a network firewall: The difference between a network-based firewall and a Web Application Firewall is that the network firewall is separate from the application and runs on another server, while a WAF runs as a part of the WordPress process. The very best hosting providers, like Kinsta, are so good that you don’t need an application firewall plugin installed in your WordPress site. Sucurri and Cloudflair Premium are two other providers of network firewall service. In these cases, you route, via your DNS records, all traffic through their firewalls and they pass it through to your site. This requires a lot of configuration, monitoring, and maintenance to protect without disrupting legitimate traffic. These are premium services and cost prohibitive for many users. If you can afford the premium services, then go for it. They have the added benefit of being able to mitigate denial of service attacks. This is a best practice if running a high-profile site or major ecommerce store.
Enforce strong passwords: There are plugins available that will force strong passwords. This is a good idea for a membership or other type of site where there are a lot of users.
Real time backups: If you are running a busy ecommerce site, then you will also likely need real time backups of ecommerce transactions. Failure to have backups could mean lost order information. Several companies in the WordPress ecosystem provide this and it is a premium service.
Use platform for updating multiple sites if applicable: If you manage more than a few sites you know that updates can become cumbersome, leading to neglect. There are platforms that allow you to easily check and apply updates across multiple sites. The bottom line is that you need to check for updates regularly, not less than once a week. Most professionals check for updates daily. If you manage multiple sites you need to be using a platform that makes this easier.
Third party penetration testing: Penetration testing is required by the credit card payment industry if you have the billing form embedded on your site. Most sites use forms hosted by the cart provider or use special popup forms where no data is entered or stored on the site itself. There are other situations where third party penetration testing makes sense. For example, when a site is for a high profile political candidate or it is used as the face for a high profile company.
Disaster recovery plan: Tornadoes, hurricanes, floods, cut power lines, hacks, denial of service attacks and other unforeseen events may disrupt the ability of your site to be served by your hosting company. If you use essential third-party platforms, such as a video hosting provider, do you have a copy of the videos? The idea here is to have a plan in place for quickly bringing a site up in another location and restore operations. This is a good tool for determining the level of preparedness needed. What is the tolerance for downtime? The answer to that question can help in judging the adequacy of the plan.
User Account Audits: If the site has a large number of users then have regularly scheduled reviews of user accounts. If the organization has seasonal spikes of activity then schedule these during the slowdown when volunteers or temporary employees typically leave.
Summary List of WordPress Lockdown Steps
So, here is a summary list of lock down steps, which I think constitute best practices. I think we want to be sure that they are in place and having them in place provides some reassurance that the attack surfaces have been covered. I’ve marked some as required, some as situational, and some as optional. In relation to the optional steps, I’d suggest applying them if it is easy to do so. For instance, if the plugins you are using offering it as an option. Otherwise, I think it is a matter of preference.
I realize that you may conclude that some of the steps I consider “required” are just “optional,” or the other way around. Please share your views in the comments below if you think I got it wrong or missed something important.