Improving HTTPS Website Security Level

HTTPS finally spreads around the web and is getting more and more the de facto standard for websites. A few months ago Mozilla released its tool Observatory for testing website security level. It rates in form of grades from A+ (best) to F (worst). Following you’d see how to reach an A+ on your website and how to implement it in WordPress.

Basics

First of all you’ll need – of course – an HTTPS encrypted website. If you don’t have it right now visit (for example) Let’s Encrypt project for details.

Now check your website by visiting Observatory’s homepage and pasting your URL. You’ll propably get a result like these:

You can improve website security level by implementing a couple of server headers. These can be set using different ways, for example via PHP as shown below.

Recommended security headers

To get an A+ from Observatory you have to set following headers (click on name for details):

  • Content-Security-Policy
    • Defines from what sources your content is allowed to be loaded. Default should be 'self' only allowing content from your own website. If you have to use content from other websites, e. g. Google Fonts or Gravatar, you should only load it from HTTPS encrypted sites. Additionally directive frame-ancestors controls framing of your website in modern browsers
    • Recommended value: default-src: 'self'; frame-ancestors: 'none'
    • Optional: Overwrite concrete -src definitions to enable functionalities, e. g. script-src: https: for loading scripts from external sites
    • No go: Usage of 'unsafe-inline' as Observatory will punish it (especially in script-src)
  • X-Frame-Options
    • Disables framing of your website in older browsers (see also Content-Security-Policy)
    • Recommended value: DENY
  • X-Content-Type-Options
    • Disables loading content without correct file type (only loads what pretends to be an image if it is actually an image)
    • Recommended value: nosniff
  • X-XSS-Protection
    • Prevents XSS attacks in older browsers
    • Recommended value: 1; mode=block
  • Strict-Transport-Security
    • Tells browsers to only load your website over HTTPS connection for given amount of time
    • Recommended value: max-age=15768000 (half a year)
    • Optional: Set a time frame longer than 15768000 seconds
    • No go: Set a time frame shorter than 15768000 seconds (half a year) or longer than 31536000 seconds (a year)
  • Permanent HTTP Redirection
    • Redirects all incoming HTTP requests to HTTPS. For example if you call http://example.com/somerequest it will redirect it automatically to https://example.com/somerequest preserving given request parameter (“somerequest”)
    • Set this directly in server config or use PHP code below

If you’ve set all headers you’ll get a ranking like following

Nota bene: As you can see I’m using style-src: 'unsafe-inline' because my template is requiring it. But it’s still A+ so I’m fine with that

Implementing security headers in WordPress

In admin panel go to Appearance > Editor and edit Main Index Template (index.php).

Insert after first <?php

// Permanent HTTPS Redirect
if (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == "off") {
  header('HTTP/1.1 301 Moved Permanently');
  header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
  die();
}

// Security Headers
// https://wiki.mozilla.org/Security/Guidelines/Web_Security
$cspHeader = array();
$cspHeader['default-src']       = "'self'";
$cspHeader['font-src']          = "data: https:";
$cspHeader['img-src']           = "https:";
$cspHeader['style-src']         = "https: 'unsafe-inline'";
$cspHeader['frame-ancestors']   = "'none'";
header("Content-Security-Policy: " . implode('; ', array_map(function ($key, $value) { return $key . ' ' . $value; }, array_keys($cspHeader), $cspHeader)));
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');
header('X-XSS-Protection: 1; mode=block');
header('Strict-Transport-Security: max-age=15768000');