A number of users and developers within the WordPress community finally realized that having a SSL certificate gives us more than just a “lock icon” in the browser. Configuring a SSL can be more than just setting URLs.

Everyone has lately heard about the security headers, things like X-Frame-Options or Expect-CT. But what are they? And what’s the best way of configuring them?

To be brief: all of those headers allow us to establish rules for HTTP requests capable of avoiding particular types of attack. The X-Frame-Options header, for instance, provide clickjacking protection, while Strict-Transport-Security protects against main-in-the-middle attacks such as protocol downgrade attacks and cookie hijacking.

All HTTPS headers in WP you should be using

If your website or app has SSL support, you should be using and configuring security headers that might be preventing your app from several types of attacks. But before diving into the coding, let’s recap what are those headers, and the reason for using each one of them (source: https://securityheaders.com).

X-Frame-OptionsX-Frame-Options tells the browser whether you want to allow your site to be framed or not. By preventing a browser from framing your site you can defend against attacks like clickjacking.
X-Content-Type-OptionsX-Content-Type-Options stops a browser from trying to MIME-sniff the content type and forces it to stick with the declared content-type. The only valid value for this header is “X-Content-Type-Options: nosniff”.
X-XSS-ProtectionX-XSS-Protection sets the configuration for the XSS Auditor built into older browsers. The recommended value was “X-XSS-Protection: 1; mode=block” but you should now look at Content Security Policy instead.
Referrer-PolicyReferrer Policy is a new header that allows a site to control how much information the browser includes with navigations away from a document and should be set by all sites.
Strict-Transport-SecurityHTTP Strict Transport Security is an excellent feature to support on your site and strengthens your implementation of TLS by getting the User Agent to enforce the use of HTTPS.
Expect-CTExpect-CT allows a site to determine if they are ready for the upcoming Chrome requirements and/or enforce their CT policy.
Content-Security-PolicyContent Security Policy is an effective measure to protect your site from XSS attacks. By whitelisting sources of approved content, you can prevent the browser from loading malicious assets. Analyse this policy in more detail. You can sign up for a free account on Report URI to collect reports about problems on your site.

As we are mostly talking about WordPress here, some of those HTTP headers can be configured with “obvious” values. In other words, for some of those headers, values will be basically the same for almost any WP website or app.

So, if we are thinking about building a script for implementing them, part of the headers can be assumed as “constant”. With that in mind, let’s move to the next step – a class or library to set the “basic” headers automatically (for those usually constant) and configure the remaining.

A single step

Under WordPress code, we can use two different hooks for including or managing HTTP headers: the action send_headers and the filter wp_headers. In theory, HTTP headers could be added and managed using any of the hooks. However, we tend to rely more on the action, rather than the filter.

The difference in the coding is simple. If you opt for the filter, that means you’ll need a function that pass one argument , the $headers array, add or modify the elements in that array and returns a new array as a result. You should be also checking for HTTPS.

if (! empty($_SERVER['HTTPS'])) {
  function add_secure_header($headers) {
    $headers['strict-transport-security'] = 'max-age=31536000; includeSubDomains';
    return $headers;
  }

add_filter('wp_headers', 'add_secure_header');
}

The same can be achieved by using the action – no need for passing any arguments in the function, which returns void. In this case, the code would look like this:

if (! empty($_SERVER['HTTPS'])) {
  function add_secure_headers() {
    header( 'Strict-Transport-Security: max-age=10886400' );
  }
  add_action( 'send_headers', 'add_secure_headers' );
}

Easy, huh? Add all those headers, respective values, hook your function using either the action or the filter, and done. But couldn’t it be more automatic and, at the same time, bring a bit of good PHP style to your code?

A class to manage that

The idea is simple: as class that adds all “obvious” secure headers automatically, and allows us to either modify their values or add new headers. We are working in something like this – for the first part of our class, we add a variable that holds all headers and values, and already brings some of them by default.

The same class is hooked to send_headers and has methods to set headers in addition to those already listed, and return a list of all headers from the variable $toApply.

class Headers {

    public $toApply = [
    	'X-Frame-Options' => 'SAMEORIGIN',
    	'X-Content-Type-Options' => 'nosniff',
    	'X-XSS-Protection' => '1; mode=block',
    	'Referrer-Policy' => 'no-referrer-when-downgrade',
    	'Strict-Transport-Security' => 'max-age=31536000; includeSubDomains',
    ];
    //...

    public function set(string $header, string $value) {
    	$this->toApply[$header] = $value;
    }

    public function list() {
    	return $this->toApply;
    }
}

This logic allows you to create a no-brainer for adding HTTP headers in any new website. The only thing you need is to copy this class or requiring it using Composer (yeah, we did it for you).

This class is to be updated in the future, to allow a better configuration of the secure headers individually. Some improvements regarding cookies should be also implemented eventually.

Check the Github repo – it worth looking at this approach, as those several lines and details can be set up in WordPress with no more than the code below.

use WPH\Security\Headers;

require __DIR__ . '/vendor/autoload.php';

$sec_headers = new Headers();
$sec_headers->set('Content-Security-Policy', 'connect-src "self"');

Leave a comment

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