There are many options to make a WordPress website more secure. For some of those options you might use additional plugins. But there is an easy way to increase the security by setting only some server settings. But before I go into details, let’s find out how to get a current security status of your site.
An excellent tool to test your website for security is the Mozilla Observatory tool. This tool scans not only the headers you server is sending, it will also scan TLS and SSH settings and will use some third-party tools to give you a brief overview. A result might look like this, before you adjust any settings:
Further down the page you will see all the tests that were passed and those who have failed, leading to this very bad score. In this example, the following test scores:
|Content Security Policy||Pass||Score -25||Reason Content Security Policy (CSP) header not implemented|
|Cookies||Pass||Score 0||Reason No cookies detected|
|Cross-origin Resource Sharing||Pass||Score 0||Reason Content is not visible via cross-origin resource sharing (CORS) files or headers|
|HTTP Public Key Pinning||Pass||Score 0||Reason HTTP Public Key Pinning (HPKP) header not implemented (optional)|
|HTTP Strict Transport Security||Pass||Score 0||Reason HTTP Strict Transport Security (HSTS) header set to a minimum of six months (15768000)|
|Redirection||Pass||Score 0||Reason Initial redirection is to HTTPS on same host, final destination is HTTPS|
|Referrer Policy||Pass||Score 0||Reason Referrer-Policy header not implemented (optional)|
|Subresource Integrity||Pass||Score -50||Reason Subresource Integrity (SRI) not implemented, and external scripts are loaded over HTTP or use protocol-relative URLs via |
|X-Content-Type-Options||Pass||Score -5||Reason X-Content-Type-Options header not implemented|
|X-Frame-Options||Pass||Score -20||Reason X-Frame-Options (XFO) header not implemented|
|X-XSS-Protection||Pass||Score -10||Reason X-XSS-Protection header not implemented|
Not all of those failed test can be fixed for a WordPress website, but we can improve on some things.
Set server headers for better security
In this blog post we will try to get the website to a “B” rating at least. To achieve this, we will add some server headers to increase the security.
On an Apache webserver, which many shared hostings are using, you can set those headers using the
.htaccess file in the root directory of your WordPress installation. Simply add these lines to the start or end of the file:
<IfModule mod_headers.c> Header always set X-Frame-Options "SAMEORIGIN" Header always set X-XSS-Protection "1; mode=block" Header always set X-Content-Type-Options "nosniff" Header always set Referrer-Policy "no-referrer-when-downgrade" Header always set Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" </IfModule>
If you use the nginx webserver, you have to set those headers in the configuration files, either globally or per site. In the configuration file, add these lines:
add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "no-referrer-when-downgrade" always; add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
You don’t have to understand all those settings. The
Content-Security-Policy is the one where we need to use a not so secure option, as otherwise your WordPress site will most break.
After we added those changes we will hopefully have passed a lot more tests. This is how it looks like on the example site:
I was expecting a “B” rating. But for some reasons it was only a “D” rating. The “Subresource Integrity” was still having a score of “-50”, so I searched for the reasons. I’ve found an embedded newsletter form using a “protocol-relative URL”. Additionally the plugin “Google Analytics for WordPress by MonsterInsights” was adding the script tag for the Google Tag Manager with a protocol-relative URL as well. Thankfully there was a filter I could use to overwrite the path adding the HTTPS protocol using a must-use plugin.
After fixing those changes and scanning the page again (you can initialize a rescan only every 5 minutes), I got the result I was hoping for:
Improving the security of a WordPress site does not always needs the use of additional plugins. Sometimes a few lines of code in your server configuration is all you need. As this is also possible on most shared hostings using the
.htaccess file, there is no reason not to add it to your site as well.