Better security for WordPress with secure server headers

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.

Mozilla Observatory

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:

Mozilla Observatory result before optimizations

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:

TestPassScoreReason
Content Security PolicyPass Score -25Content Security Policy (CSP) header not implemented
CookiesPass Score 0No cookies detected
Cross-origin Resource SharingPass Score 0Content is not visible via cross-origin resource sharing (CORS) files or headers
HTTP Public Key PinningPass Score 0HTTP Public Key Pinning (HPKP) header not implemented (optional)
HTTP Strict Transport SecurityPass Score 0HTTP Strict Transport Security (HSTS) header set to a minimum of six months (15768000)
RedirectionPass Score 0Initial redirection is to HTTPS on same host, final destination is HTTPS
Referrer PolicyPass Score 0Referrer-Policy header not implemented (optional)
Subresource IntegrityPass Score -50Subresource Integrity (SRI) not implemented, and external scripts are loaded over HTTP or use protocol-relative URLs via src="//..."
X-Content-Type-OptionsPass Score -5X-Content-Type-Options header not implemented
X-Frame-OptionsPass Score -20X-Frame-Options (XFO) header not implemented
X-XSS-ProtectionPass Score -10X-XSS-Protection header not implemented
Mozilla Observatory Test Scores

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.

Apache

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 "strict-origin-when-cross-origin"
Header always set Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'"
</IfModule>

nginx

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 "strict-origin-when-cross-origin" 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.

New result

After we added those changes we will hopefully have passed a lot more tests. This is how it looks like on the example site:

Mozilla Observatory result after optimizations

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.

Final result

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:

Mozilla Observatory final result

It’s possible to get a “B+” rating, but only if you don’t embed any JavaScript files from an external domain. Otherwise you will fail the “Subresource Integrity” test with the result “Subresource Integrity (SRI) not implemented, but all external scripts are loaded over HTTPS”.

Conclusion

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.

Posted by

Bernhard is a full time web developer who likes to write WordPress plugins in his free time and is an active member of the WP Meetups in Berlin and Potsdam.

Leave a Reply

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