There are a ton of things we have to consider when making our website or web-application as secure as possible. A good starting point might be looking into HTTP Security headers.
Why? Because they are a one-off effort and they are easy to implement since the only thing we need to do are little changes to our preferred web servers configuration.
In this article we'll explore the most important ones and give advice on how to test out our security header configurations.
Starting off with the Strict-Transport-Security header, this header basically tells the browser that our website can only be reached via
https instead of
Strict-Transport-Security: max-age=<expire-time> Strict-Transport-Security: max-age=<expire-time>; includeSubDomains Strict-Transport-Security: max-age=<expire-time>; preload
max-age directive defines how long (in seconds) the browser should remember that the website is only reachable via
includeSubDomains directive defines what it's name implies, namely that the browser should apply this knowledge to all subdomains of the domain as well.
preload directive is in fact nothing that is officially part of the header specification. Google is maintaining an HSTS preload service with which we can register our website, telling each browser about our
https preference even before the first request hits our web servers.
The Content-Security-Policy (CSP) Header is another added security layer that helps to detect and mitigate certain types of attacks such as Cross Site Scripting (XSS) and data injection attacks.
It works by providing the browser with a list of approved ressources and ressource origins that it is allowed to load or act upon.
TDLR: To easily generate the CSP header, you can use the generator from www.cspisawesome.com, which makes the process really easy.
Content-Security-Policy: default-src 'self' Content-Security-Policy: default-src 'self' *.example.com Content-Security-Policy: default-src 'self'; img-src *; script-src data: scripts.example.com
As we can see the Content Security Header can be composed of a variety of different directives like
media-src to name a few. For a complete list we can check out the MDN docs.
default-src obviously tells the browser from which origins it should be allowed to load ressources by default.
Via the other directives like
img-src we are able to override our configuration for the
default-src and specify our own custom set of rules only for images.
Additionally to the classic origins or origin patterns called host-sources we are also able to define scheme-sources for scheme based restrictions such as
Additionally you might have already noticed
'self' doesn't fall into either of those two source categories, that is because it is a special source type, referring to the current origin of the requested page.
Other important special source categories are:
'unsafe-inline'which allows inlined content within the HTML markup to be acted upon or displayed.
'none'which specifically sets the rule to not allow anything for the specific directive.
For a complete list we can check out the MDN docs again.
The X-Frame-Options header allows us to tell the browser if it should be allowed to render our website or webpage within an
X-Frame-Options: DENY X-Frame-Options: SAMEORIGIN
Allowed values for this header are
DENY which signals browsers that it should not be possible to embed the current site into another one, and
SAMEORIGIN which signals that the site can only be embedded in another site of the same origin.
The X-Content-Type-Options header prevents browsers from guesssing the content type of a ressource instead of listening to the
Content-Type header value.
The only possible value is
nosniff which basically enables the functionality and signals the browser to strictly listen the Content-Type header sent within the response.
The Referrer-Policy header is a way to control how much referrer information that is sent via the
Referrer header should be included with requests.
Referrer-Policy: no-referrer Referrer-Policy: no-referrer-when-downgrade Referrer-Policy: origin Referrer-Policy: origin-when-cross-origin Referrer-Policy: same-origin Referrer-Policy: strict-origin Referrer-Policy: strict-origin-when-cross-origin Referrer-Policy: unsafe-url
Possible directives for this header are:
no-referreromits the header altogether.
no-referrer-when-downgrade(default) Origin, Path and Query string are sent as long as the security protocol level stays the same or improves
originonly sends the origin in the header
origin-when-cross-originOrigin, Path and Query string will be sent for same origin request, for cross-origin requests only the origin will be sent.
same-originreferrer information will only be sent to same origin sites.
strict-originonly sends the origin information when the security protocol level stays the same or improves.
strict-origin-when-cross-originsends the Origin, Path and Query string to same origin requests and sends only the origin information if the security protocol level stays the same or improves.
unsafe-urlsends Origin, Path and Query all the time without any constraints.
The Expect-CT header prevent misissued certificates from being used. This happens by allowing website to report and optionally enforce so called Certificate Transparency requirements.
As soon as we are enabling this header for our website, we are requesting the browser to verify whether or not the certificate appear in the public Certifcate Transparency logs.
Expect-CT: max-age=86400, report-uri="https://example.com/expect-ct/report"
max-age directive we are able to define how long the browser should be allowed to remember the last lookup.
report-uri directive we are explicitly telling the browser to report any issues to the specified uri.
The Permissions-Policy header, previously known as Feature-Policy header, provides a mechanism to allow or deny the use of certain browser API features.
Permissions-Policy: <directive>=(<allowlist>) Permissions-Policy: geolocation=(), microphone=('none'), battery=('self'), payment=()
The header consists of multiple "directive to allowlist" definitions, just as we can see in the example.
There are various directives we can use, spanning over all browser based API features currently available, some of the more common are
fullscreen. For a more detailed list check out the MDN docs.
Allowed values for our
<allowlist> would be:
'self'meaning that the feature will be allowed in this and all nested contexts, with the restriction that they must have the same origin
'src'meaning that the feature will be allowed in iframes, as long as the documented loaded into the iframe has the origin
'none'meaning the feature is disabled in all browsing contexts. The same goes for an empty list.
<origin(s)>meaning that the feature is allowed only for ressources matching the specified orgins (separated by space)
How to test our security headers?
Having all those headers implemented in our servers configuration is one part, the other part would be to verify if our efforts were any good.
This is where securityheaders.com comes into play, they provide us with an easy way to test our setup for all of the described headers above and give our website a ranking of A+ for superb to F for "there is some more work to be done".
Hey cool, you made it! We hope our article was helpful for you and you managed to find all the information regarding security headers you were looking for!