Nginx: How to get an A (or A+) rating on securityheaders.io

Some time ago, I wrote about how to set up Nginx to get an A+ rating on SSL Labs (focusing specifically on an ECDSA certificate, but you can certainly achieve the same with a (more common) RSA certificate). SSL Labs' test is very comprehensive, warning the user of most potential problems, including SSL/TLS implementation bugs (update your software!), misconfigurations, problems with the certificate itself, etc.. But there is another similar tool, securityheaders.io, which focuses on something different: security-related headers. Such headers are sent by the web server (such as Nginx or Apache) and affect browsers' security in several ways, unrelated to encryption, protocols or the certificate used (these are tested by SSL Labs).

For more details about those headers, I'd suggest you navigate to securityheaders.io itself, and then check your site in it, then follow the links for each suggestion. Meanwhile, if your site uses Nginx, here's a "quick and dirty" guide for getting an A rating (and, yes, I'll mention what you'd need for an A+ rating, and also why I choose not to try for one).

Nginx setting Explanation
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload"; Enforces HTTPS on the entire site. Don't use if you still need to provide HTTP, of course.
add_header X-Content-Type-Options nosniff; Prevents browsers from trying to "guess" MIME types and such, forcing them to use what the server tells them.
add_header X-Frame-Options SAMEORIGIN; Stops your site from being included in iframes on other sites.
add_header X-Xss-Protection "1" always;  Activates cross-scripting (XSS) protection in browsers.
add_header Referrer-Policy "unsafe-url";  Makes the site always send referrer information to other sites. NOTE: this is not the most secure setting, but it's the one I prefer; see below.
add_header Content-Security-Policy "default-src https: data: 'unsafe-inline' 'unsafe-eval'";  Forces TLS (don't use if you still need to provide HTTP); prevents mixed content warnings. NOTE: again, this is not the most secure setting; see below.

You're probably wondering about the last two settings. I choose to send referring information to other sites for a simple reason: I like to see where my own visitors come from (I don't sell, share or monetize that in any way, it's just for curiosity's sake), and I'm a firm believer in treating others as I want to be treated. If you don't care about that, you may want to change this to "no-referrer-when-downgrade", or "strict-origin".

As for the Content Security Policy, anything more "secure" than the above prevents (or at least makes it a lot more headache-inducing) the use of inline scripts and/or external scripts, which would mean no external tools/scripts/content (or at least a lot of work in adding every external domain to a list of exceptions), and a lot of hacking on software such as WordPress (seriously: add the setting, but then remove the "unsafe-*" options and see what stops working...). You might use the most paranoid settings for an internally developed, mostly static site, but I fail to see the point. So, this and the paragraph above are the reasons for an A rating, instead of an A+.

6 Replies to “Nginx: How to get an A (or A+) rating on securityheaders.io”

  1. Hey, at some websites it is showing “always” at the end, like add_header X-XSS-Protection “1; mode=block” always;
    What is the difference between them ?

    1. According to the Nginx docs:

      Adds the specified field to a response header provided that the response code equals 200, 201 (1.3.10), 204, 206, 301, 302, 303, 304, 307 (1.1.16, 1.0.13), or 308 (1.13.0).

      (…)

      If the always parameter is specified (1.7.5), the header field will be added regardless of the response code.

      In this particular situation, it’s probably a good idea to include the “always” bit, to add the security headers to other response codes (404, 500, etc.).

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: