WordPress security & hardening, the definitive guide

Last updated on November 25th, 2022 by Mark Grima. Filed under WordPress Security

Featured image *WordPress security*

WordPress is massively popular. Around every one in five sites on the Internet uses WordPress in some form. Be that to run a humble blog, a multi-site Content Management System (CMS), or an e-commerce site, WordPress has become a ubiquitous part of the internet. As a result, it is no surprise that WordPress websites are a very popular target for both experienced hackers and script kiddies alike.

The last thing any webmaster wants is to find out that their website has been hacked, perhaps taken hostage, and is part of a botnet spreading malware or partaking in Denial of Service (DoS) attacks. This article will share several tips and strategies to help you harden your WordPress website for increased website security.

Table of contents

Is WordPress secure?

This is a question many system administrators ask, and rightfully so. While WordPress is overall well-built and secure, it has a reputation for being prone to security vulnerabilities and not being “enterprise-grade.” That reputation is not exactly fair.

WordPress is an incredibly popular software package. Many people work on WordPress, including development and testing. It remains highly customizable, which is one of the reasons it has achieved such popularity. This customizability, however, can introduce vulnerabilities, increasing the overall security risk.

WordPress customization can take many forms, including the configuration of WordPress itself and the environment in which it runs, as well as the installation of plugins and themes, among other things. While not all customizations necessarily introduce risks, unless they’re done properly, they can lead to security issues.

Plugins and themes

WordPress can be customized in countless ways. Some of these customizations can introduce code and misconfigurations that affect WordPress security. One popular way to customize WordPress is through plugins and themes.

WordPress plugins and themes vary far and wide in terms of quality and safety. While a lot of work has been done by the WordPress team to help developers build more secure plugins and themes, not all developers follow security best practices. This is often noticed when using poorly maintained plugins or plugins obtained from a sketchy source.

Before we continue discussing WordPress plugins and themes, let’s first understand what a WordPress plugin actually is. Plugins are simply custom PHP code that WordPress runs to extend its functionality. For a more detailed and technical explanation, refer to What are WordPress plugins?

Similarly, WordPress themes allow for the customization of the visual aspects of your WordPress site. From an attacker’s perspective, there is very little difference between the two since both can be abused to run malicious code.

Run less software

So how can you tell if a plugin is malicious or not? That’s a complicated question, but fortunately, we have an answer for you. We have written about this extensively in how to choose the best WordPress plugin for your WordPress website.

Even though you may make all the necessary research, there are chances, however slim, that the plugin might introduce security threats. So one of the ways to reduce your risk is to only run the software you absolutely need and trust. Before installing a new WordPress plugin, ask yourself if you really need to install that plugin. Can a small code snippet in a site-specific plugin do the trick, or do you legitimately need a fully-blown plugin?

Important — be very vigilant with code snippets you find on the Internet. Never use a piece of code unless you fully understand what it’s doing — just because it’s on StackOverflow, it doesn’t mean it’s safe to use.

If you genuinely need to run a plugin, ensure it’s actively maintained and regularly updated, as we explain in our guide. As a rule of thumb, the more downloads and recent updates the plugin or theme has, the safer it is. It shows that it is in wide use and that it is being actively maintained by its authors. This does not mean that the plugin will never have a vulnerability. However, if a vulnerability is found, the developer is more likey to act quickly and issue a fix.

Try to avoid plugins that don’t have many downloads and, critically, do not have an active community and regular updates. If something hasn’t received an update within a year, try to avoid it.

Observe the least privileged principle

WordPress does not need to use the MySQL root user to connect to its database. Nor does every WordPress user need to have the role of an administrator. Similarly, running most programs as a privileged user is not a good idea unless there is a specific reason to do so.

Security best practices dictate that applications should always be given the least privileges possible that allow them to work properly, with any additional privileges disabled. This practice is commonly referred to as the principle of least privilege.

Let’s hypothetically assume WordPress is connecting to a database with a privileged user account. In the event of a WordPress plugin containing an SQL injection vulnerability, an attacker may be able to not only run SQL queries as an administrator, but in some cases, they may even be able to execute operating system commands. If an attacker successfully executes operating system commands, they may be able to carry out reconnaissance and escalate the attack to include other systems.

Running software with administrative privileges or providing users with more access than necessary is a security risk not worth assuming. It goes against the tried-and-tested least privilege principle since it allows an attacker to inflict more damage in the event of a security breach.

The good thing with WordPress is that it has several built-in user roles, which you can use to assign different privileges to different users, depending on their requirements. We have written extensively about this in how to use WordPress user roles for improved WordPress security.

Update your WordPress plugins and themes

WordPress plugin and theme updates are important to benefit from new functionality, bug fixes and to patch security vulnerabilities. Both plugins and themes are easy to update within the WordPress interface.

Some commercial plugins will likely have their own mechanisms to keep plugins up to date; however, in most cases, this is transparent to the users. Nonetheless, just make sure that whatever update system is being used, you keep your plugins and themes up to date.

Do not use ‘nulled’ WordPress plugins and themes

WordPress nulled plugins
WordPress is released under the GNU GPL. Without going into much detail, the GPL license allows for anyone to freely distribute GPL-licensed software. This includes commercial/premium GPL-licensed WordPress themes and plugins. As such, it may not be illegal to download a modified, usually referred to as nulled, premium theme or plugin and use it for free.

However, as you may have already guessed, aside from not supporting the plugin developer, you are very unlikely to receive updates for nulled plugins. What’s more, unless you’re a developer, you have no way of knowing if the code of this plugin has been modified to do something nefarious.

Keep WordPress up to date

Just like you should keep your plugins and themes up to date, you should also make it a point to keep the version of WordPress you’re running updated to the latest version. Fortunately, this is now much easier than before, with critical security updates installed automatically. Of course, unless you explicitly disable this functionality.

Aside from new features, improvements, and bug fixes, WordPress core updates also contain security fixes that may protect you from attackers exploiting your WordPress website.

WordPress Hosting

WordPress hostingWhere and how you choose to host your WordPress site will highly depend on your requirements. While there is nothing wrong with hosting and managing WordPress yourself, if you are either not technically savvy, or you want to make sure to meet most of the WordPress security basics without doing a lot of heavy lifting, you may want to opt for a managed WordPress hosting provider such as Kinsta or WP Engine.

Since we have had websites hosted with both hosts, we have written about them. In our customer stories, we highlight our experience with them. To learn more about our experience using hosting companies, read our WP Engine and Kinsta customer story. Managed WordPress hosting abstracts away many security decisions and configurations you need to otherwise worry about yourself.

Naturally, managed WordPress hosting may also not be for you. While hosting plans come in all shapes and sizes, you may opt to host WordPress yourself, especially if you’re budget constrained. Self-hosting WordPress also gives you greater control over your WordPress installation. To learn more about all the different WordPress hosting options and what might work best for you, refer to the guide to choosing WordPress hosting.

WordPress dashboard

Your site’s WordPress dashboard is a place you don’t want anyone unauthorized to access. While there are some sites that have legitimate reasons to allow public users to log in using the WordPress dashboard, this is a huge security risk and must be very carefully considered.

Fortunately, most WordPress websites do not have this requirement and, as such, should prevent access to the WordPress dashboard. There are several ways to do this, and you should pick what works best for you.

A common practice is to restrict access by password-protecting the WordPress Admin (wp-admin) pages. Another solution would be to only allow access to /wp-admin to select IP addresses. Access can also be restricted using the htaccess file.

Disable registration

By default, WordPress does not allow public users to register on your WordPress website. To confirm that user registration is disabled:

  1. Head over to the Settings > General page in your WordPress dashboard area
  2. Navigate to the Membership section
  3. Ensure that the checkbox next to Anyone can register is not selected.

Credentials

Like any other website, access to your WordPress dashboard is only as strong as your credentials are. Enforcing strong WordPress password security is a crucial security control of any system, and WordPress is no exception.

While WordPress does not have any way to set a password policy out of the box, a plugin such as WPassword is an absolute must to enforce password strength requirements across all of your users who have access to the WordPress dashboard.

Once you enforce strong password security on your website, use WPScan to test for weak WordPress credentials to make sure no account is still using weak passwords.

Limit login attempts

While users tend to forget their password from time to time, numerous concurrent failed logins may indicate a hacking attempt. Bots can generate an incredible number of failed login attempts in a short period of time. This can negatively impact the performance of your website and if it’s an actual attack, might result in a breach.

As an admin or website owner you can use a password security plugin such as WPassword to limit failed login attempts. This should apply to the WordPress login page and any other login page you might have.

Two-Factor Authentication (2FA)

Two-Factor Authentication

Another essential security control for your WordPress dashboard is to require two-factor authentication. Two-factor authentication (2FA) makes it significantly harder for an attacker to gain access to your WordPress dashboard should they manage to uncover a user’s password (e.g., an attacker may discover a user’s password from a data breach).

Luckily, it is very easy to set up two-factor authentication on WordPress. There are several high-quality plugins you can use to add this functionality. Read the best two-factor authentication plugins for WordPress for a highlight of the top 2FA plugins available for WordPress.

Hardening WordPress core

Even though WordPress’s core is a secure piece of software, it doesn’t mean that we can’t harden it further. The following are several hardening actions specific to the WordPress core.

Make sure debug logging is disabled

WordPress allows developers to log debug messages to a file (this being /wp-content/debug.log by default). While this is perfectly acceptable in a development environment, keep in mind that this file can also be easily accessed by an attacker if the same file and/or settings make their way to production.

WordPress debug is disabled by default. Though it is always better to double check it is — ensure you do not have the WP_DEBUG constant defined in your wp-config.php file, or explicitly set it to false. Refer to the WordPress debug guide for a list of all the debugging options.

If, for some reason, you need the WordPress debug logs on your live website, log to a file outside of your web server root (e.g.,/var/log/wordpress/debug.log). To change this, simply add the following line:


define('WP_DEBUG_LOG', '/path/outside/of/webserver/root/debug.log');

Disable XML-RPC

The WordPress XML-RPC specification was designed to allow communication between different systems. This means that virtually any application can interact with WordPress. The WordPress XML-RPC specification has historically been important for WordPress. It allows it to interact and integrate with other systems and software.

The good thing is that XML-RPC has been superseded by the WordPress REST API. To highlight some of the security concerns around XML-RPC; it’s interface has been the source of numerous security vulnerabilities over the years.

It also can be used by attackers for username enumeration, password brute force attacks, or denial of service (DoS) attacks via XML-RPC pingbacks.

Therefore unless you are actively using XML-RPC and have appropriate security controls in place, you should disable it. Since this is something easily achievable without installing a third-party plugin, we’ll cover how to do so below.
While you may simply configure your web server to block access to /xmlrpc.php, a preferred method of doing this is to explicitly disable XML-RPC using a built-in WordPress filter. Simply add the following to a plugin file and activate it on your site.

 

add_filter('xmlrpc_enabled', '__return_false');

Heads up

  • It’s a good idea to use a WordPress must use plugin for this and other similar code snippets.

Restrict the WordPress REST API

In the same vein as XML-RPC, the WordPress API is the modern way for third-party applications to communicate with WordPress. While it is safe to use, it is advisable to restrict some functions within it to prevent user enumeration and other potential vulnerabilities. Unlike XML-RPC, WordPress does not provide a simple, native way to disable the REST API entirely (it used to, but this got deprecated, so it’s wise not to do so any longer); however, you can restrict it.

As is typical with WordPress, you may either use a plugin to achieve this, or you can add the following filter to a plugin file and activate it on your site. The following code will disable the WordPress REST API for anyone who is not logged in by returning an unauthorized HTTP status code (status code 401) using the rest_authentication_errors WordPress hook.

 
add_filter( 'rest_authentication_errors', function( $result ) {
if ( ! empty( $result ) ) {
return $result;
}
if ( ! is_user_logged_in() ) {
return new WP_Error( 'rest_not_logged_in', 'You are not currently logged in.', array( 'status' => 401 ) );
}
return $result;
});

Additionally, the WordPress REST API enables JSONP by default. JSONP is an old technique for bypassing the browser’s same origin policy before modern browsers supported CORS (Cross-origin Resource Sharing). Since this could potentially be used as a step in an attack by an attacker, there is no real reason for this to be enabled. It is recommended to disable it using the rest_jsonp_enabled WordPress filter using the following PHP snippet.

 
add_filter('rest_enabled', '__return_false');

Refer to the filter’s documentation for more information about it.

Prevent WordPress version disclosure

Like many other web applications, by default, WordPress discloses its version in several places. Version disclosure isn’t exactly a security vulnerability, however, this information is very useful for an attacker when planning an attack. As a result, disabling WordPress’s version disclosure features may make an attack just a little bit more difficult.

WordPress leaks a lot of version information. Luckily, this GitHub gist offers a comprehensive list of WordPress filters to disable this leakage in the form of a WordPress plugin. Of course, you can incorporate this code into any existing site-specific or must-use plugins you already have.

Prevent WordPress user enumeration

WordPress is vulnerable to several user enumeration attacks. Such attacks allow an attacker to figure out which users exist or whether a user exists or not. While this may seem harmless, remember that attackers may use this information as part of a larger attack and as such, may compromise your site security. For more information about this topic, read how to enumerate WordPress users with WPScan.

To prevent WordPress user enumeration, you’ll need to ensure that the following WordPress features are disabled or restricted.

  • Restrict the WordPress REST API to unauthenticated users
  • Disable WordPress XML-RPC
  • Don’t expose /wp-admin and /wp-login.php directly to the public Internet

Additionally, you will also need to configure your web server to prevent access to /?author=<number>. If you are using Nginx, you may use the following configuration to prevent WordPress user enumeration:

 
RewriteCond %{REQUEST_URI} ^/$
RewriteCond %{QUERY_STRING} ^/?author=([0-9]*)
RewriteRule .* - [R=403,L]

Alternatively, if you are using Apache HTTP Server, you may use the following configuration to prevent WordPress user enumeration:

 
if ( $query_string ~ "author=([0-9]*)" ) {
return 403;
}

Disable the WordPress file editor

One of WordPress’s most dangerous features is the ability to edit files from within the WordPress dashboard itself. There should be no legitimate reason why any user should need to do this, and certainly not to WordPress core. If anything, you want to ensure that you know exactly what files changed using a high-quality file integrity monitoring (FIM) security plugin.

The Website File Changes Monitor plugin, which we develop allows you to receive notifications of file changes, in real-time through email.

Any file changes to your website should happen either over a secure connection (e.g., sFTP) or, preferably, tracked in a version control repository and deployed using CI/CD.
It’s important to note that FTP should be avoided at all costs – ensure you are using sFTP instead when accessing the backend.

To disable file editing in the WordPress dashboard, simply add the following to your wp-config.php file.

 
define('DISALLOW_FILE_EDIT', true );

Disable theme and plugin management

A good WordPress security best practice is to disable plugin and theme management from the WordPress dashboard. Instead, use command line tools such as wp-cli to make these changes.

By disabling theme and plugin changes, you drastically reduce your WordPress website’s attack surface. In this case, even if an attacker successfully breaches an administrator account, they would not be able to upload a malicious plugin to escalate the attack beyond access to the WordPress dashboard.

The DISALLOW_FILE_MODS constant defined in wp-config.php disables plugin and theme updates and installation through the dashboard. It also disables all file modifications within the dashboard, thus removing the Theme Editor and Plugin Editor.

To disable the theme and plugin modifications in the WordPress dashboard, add the following to your wp-config.php file.

 
define('DISALLOW_FILE_MODS', true );

WordPress HTTPS (SSL / TLS)

Transport Layer Security (TLS) is one of the most important security measures you can undertake for your WordPress security. It’s also free and easy to set up. Note: TLS is the protocol that replaced the Secure Socket Layer, SSL. However, since the term SSL is very popular, many still refer to TLS as SSL.

When you visit your website over HTTPS (HTTP over TLS), the HTTP requests and responses are encrypted using a tls/ssl certificate and cannot be intercepted and snooped upon, or worse, modified by an attacker.

While TLS has more to do with your web server or Content Delivery Network (CDN) than your WordPress installation, one of the most important aspects of TLS (WordPress HTTPS) is enforcing it. There is a wealth of information online about how to set up WordPress HTTPS (SSL and TLS).

If you are not comfortable editing configuration files and prefer to switch to WordPress HTTPS using a plugin, you can use Really Simple SSL or WP force SSL. They are both very good and easy-to-use plugins.

Next steps for an even more secure WordPress

If you have made it this far, great, but that doesn’t mean there isn’t yet more hardening to be done. The following are a number of items you can look into to harden your WordPress website even further.

  1. Harden PHP. Given PHP is a core component of any WordPress website, hardening PHP is one of the logical next steps. We have written about this extensively in Best PHP security setup for WordPress websites.
  2. Use reputable security plugins. Quality security plugins offer advanced security features not included in WordPress natively. There are a vast amount of WordPress security plugins out there. However, be sure to pick plugins with a good reputation and, ideally, ones where premium or commercial support is available, like our high-quality security plugins for WordPress.
  3. Perform a file permissions audit. For WordPress websites running on Linux, incorrect file permissions may allow unauthorized users to access potentially sensitive files. For more information about this subject, refer to our guide to configuring secure WordPress website & web server permissions.
  4. Perform a backup file audit. Backup files accidentally left accessible may leak sensitive information. This includes configuration containing secrets that may allow attackers to gain control over the entire WordPress installation.
  5. Harden your web server
  6. Harden MySQL
  7. Add the necessary HTTP security headers
  8. Ensure you have a working WordPress backup system.
  9. Use a DDoS protection service
  10. Implement a Content Security Policy
  11. Manage exposed backup and unreferenced files.

Conclusion – This is just the first step of the WordPress security journey

Congratulations! If you followed all the above advice and implemented all the recommended security best practices, your WordPress website is secure. However, WordPress security is not a one-time fix – it is an ever-evolving, iterative process. There is a big difference between hardening a WordPress website (one-time state) vs. keeping it secure for years.

Hardening is just one of the four stages in the WordPress security process (WordPress security wheel). For a secure WordPress website all year round, you must follow the iterative WordPress security process of testing > hardening > monitoring > improving. You have to continuously test and check the security state of your WordPress website, harden the software, monitor the system, and improve your setup based on what you see and learn. For example:

  • a tool such as WPScan can help you test the security posture of your WordPress website
  • a WordPress firewall, also known as a Web Application Firewall (WAF), such as WordFence or Sucuri can protect your WordPress website from malicious known hack attacks
  • a WordPress activity log can help you go a long way – by keeping a record of all the changes that occur on your website, you can improve user accountability, know what each user is up to, and also keep an eye on all the under-the-hood activities
  • tools such as our WordPress security & management plugins can help you ensure passwords security, harden the WordPress security process, get alerted of file changes, and much more

You have all the right tools to keep your site secure. Even if you run a small WordPress website, take the time to gradually work through this guide. Ensure you don’t end up putting work into building a great website only to have it ransacked by a WordPress-targeted attack.

There is no such thing as 100% effective security. However, you’re making it considerably harder for an attacker to gain a foothold and successfully attack your WordPress website by applying the various hardening techniques covered in this guide.

5 comments

Christina Blocker 15/04/2021

wonderful article about WordPress security. I had used many security plugins over a while to protect my website. Which plugin is good for WordPress I never understand. My first website was hacked through malware. At that time I was not aware of such things. I tried hard but could not resolve myself. But I learned about some security plugins which help.

Alan.A.K 18/07/2021

Great article about wordpress security it is really helpful thanks for sharing this content

Radostin Angelov 19/07/2021

We’re glad you found this article helpful. Thanks for the feedback, Alan!

James 22/07/2021

When I tried to add the code for “Restrict the WordPress REST API” to my must use plugin, I get an error for the following line:

return new WP_Error( ‘rest_not_logged_in’, ‘You are not currently logged in.’, array( ‘status’ => 401 ) );

The error reported is:

Parse error: syntax error, unexpected ‘=’, expecting ‘)’ in /home/customer/www/thelazyspadmin.com/public_html/wp-content/mu-plugins/must-use.php on line 20

Robert Abela 23/07/2021

Hello James, thank you for your comment.

I can confirm that the code is correct and it works. Please double check what code is on line 20. It could also be other code in the file that is affecting it, so check all the code if the issue persists. All the best with finding a solution and thank you for following our website.

Leave a Reply

Your email address will not be published. Required fields are marked *

Our other plugins