An Overview of Security Headers
It goes without saying that we want the websites we build to be secure.
If you want to strengthen the security of your websites, adding some security headers is a great step to take, especially since it can be easy and inexpensive to do.
These HTTP headers get exchanged between the browser and the server and dictate how the two can communicate with each other. This can help mitigate common attacks, like cross-site scripting (XSS) and clickjacking.
If you're not overly familiar with security headers, worry not. There are some helpful tools out there such as securityheaders.com and Mozilla Observatory. These are free and fast ways to spot check your site's headers and provide recommendations to strengthen them.
In this post, we'll dive into six security headers, their purpose, and how to apply them. As a bonus, we'll provide an example of how to add them to a site hosted on Vercel.
Site content restriction headers
X-Frame-Options header
The X-Frame-Options
header is used to indicate whether or not a browser should be allowed to render a page in the following HTML elements:
<frame>
<iframe>
<embed>
<object>
It can be used to prevent clickjacking attacks by ensuring that site content is not embedded into other sites.
X-Frame-Options syntax
X-Frame-Options: DENY
When the header is given a value of DENY
, the page cannot be displayed in a frame.
X-Frame-Options: SAMEORIGIN
When it's given a value of SAMEORIGIN
, the page can be displayed in a frame, but only on the same origin as the page itself.
X-Content-Type-Options header
The X-Content-Type-Options
header is used to indicate that the MIME types in the Content-Type
headers should be followed and not be changed. This helps to prevent MIME sniffing because it specifies that MIME types are deliberately configured.
X-Content-Type-Options syntax
X-Content-Type-Options: nosniff
This configuration will block a request if the request destination is of type:
style
and MIME type is nottext/css
script
and MIME type is not a JavaScript MIME type
Domain resolution control headers
X-DNS-Prefetch-Control header
The X-DNS-Prefetch-Control
header controls, as its name suggests, DNS prefetching.
DNS prefetching is a feature by which browsers proactively perform domain name resolution on both links that the user may choose to follow and URLs for items referenced by the document (images, CSS, JavaScript, etc.). It’s performed in the background and reduces latency when a user clicks a link.
X-DNS-Prefetch-Control syntax
X-DNS-Prefetch-Control: on
A value of on
will enable DNS prefetching, which is the default browser behavior if the header isn't present.
X-DNS-Prefetch-Control: off
A value of off
will disable DNS prefetching. This configuration is useful if you don't control the links on the page or you don't want to leak information to those domains.
Strict-Transport-Security header
The Strict-Transport-Security
header informs browsers that the site should only be accessed using HTTPS and that any future attempts to access it using HTTP should be automatically converted to HTTPS.
Using this header is more secure than configuring an HTTP to HTTPS 301
redirect on the server, since in that case, the initial HTTP connection would still be vulnerable to a man-in-the-middle attack.
When using a redirect, visitors may initially communicate with the non-encrypted version of the site before being redirected. The redirect could be exploited to direct users to a malicious site instead of the secure version of the original site.
Strict-Transport-Security syntax
Strict-Transport-Security: max-age=<expire_time>
<expire_time>
is the time in seconds that the browser should remember that a site is only to be accessed using HTTPS.
Strict-Transport-Security: max-age=<expire_time>; includeSubdomains
Specifying the optional includeSubdomains
parameter will apply the rule to all of the site's subdomains.
User privacy protection headers
Referrer-Policy header
The Referrer-Policy
header controls how much referrer information should be included with requests. Referrer information is sent with the Referer
header (this may look like a typo, but it's actually a misspelling that was set in stone back in 1996).
Some examples of referrer information are:
- The address of the previous web page that a user was on when they clicked a link for the current page
- The address of a page that's loading an image or some other resource
Sharing such information can be a security problem, so the Referrer-Policy
header can be used to prevent it.
Referrer-Policy syntax
There are several different values that can be provided for this header. Let's examine each one.
Referrer-Policy: no-referrer
Providing the no-referrer
value will result in the Referer
header being omitted, so the sent request will not include any referrer information.
Referrer-Policy: no-referrer-when-downgrade
This configuration will prevent the Referer
header from being sent when navigating from HTTPS to HTTP. When navigating from HTTP to any origin, the Referer
header will be sent and will contain the full URL.
Referrer-Policy: origin
With a value of origin
, the Referer
header will include the origin but not the path.
Referrer-Policy: origin-when-cross-origin
In this case, the Referer
header will include the URL for requests to the same origin, but will include only the origin when requests are cross-origin.
Referrer-Policy: same-origin
Specifying same-origin
will result in the Referer
header only being sent for requests to the same origin. It's important to note that HTTPS to HTTP is considered a different origin.
Referrer-Policy: strict-origin
With strict-origin
, the Referer
header will include the origin but not the path, and it will only be sent for HTTPS requests.
Referrer-Policy: strict-origin-when-cross-origin
Like origin-when-cross-origin
, the strict-origin-when-cross-origin
value will result in the Referer
header including the full URL for requests to the same origin and only the origin when requests are cross-origin. The difference is that no information will be sent when navigating from HTTPS to HTTP.
Referrer-Policy: unsafe-url
Finally, with unsafe-url
, the Referer
header will always include the full URL with any request to any origin. The name is apt, because this configuration will result in leaking potentially private information from HTTPS URLs to insecure origins, so it should generally be avoided.
You can view examples of each Referrer-Policy
value on MDN.
Permissions-Policy header
The Permissions-Policy
header provides a mechanism for allowing or denying the use of browser features in its own frame and in content within any <iframe>
elements.
Permissions-Policy syntax
There are quite a few Permissions-Policy
header directives, so we won't go over all of them in this post. But here's the general syntax and an example:
// General syntax
Permissions-Policy: <directive> <allowlist>
// Example
Permissions-Policy: microphone 'none'; geolocation 'none'
In the example, the microphone and geolocation features will be disabled for all browsing contexts, including <iframe>
elements, regardless of their origin.
Bonus: Configuring security headers for Vercel
If your site is hosted on Vercel, adding security headers is as simple as updating the vercel.json
file. Add any headers you want to the headers
array, each element of which is an object that contains a source
property and a headers
property.
The source
property indicates the routes to which you want the headers to apply, and the headers
property is an array that contains the headers themselves.
Here's an example using the security headers we've discussed in this post. A source of /(.*)
will result in the headers being applied to every page.
{
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "X-Content-Type-Options",
"value": "nosniff"
},
{
"key": "X-Frame-Options",
"value": "DENY"
},
{
"key": "Referrer-Policy",
"value": "no-referrer"
},
{
"key": "Permissions-Policy",
"value": "geolocation=(), microphone=(), camera=()"
},
{
"key": "X-DNS-Prefetch-Control",
"value": "on"
},
{
"key": "Strict-Transport-Security",
"value": "max-age=15552000; includeSubdomains"
}
]
}
]
}
Note: A Permissions-Policy
value of 'none'
becomes a set of empty parentheses when configuring for Vercel.
Wrapping up
As we examined above, adding security headers can improve the security of your site in a few ways, and it's often as simple as updating a configuration file. We looked at Vercel here, but the principle applies to other hosting environments. For example, with Netlify, just update your netlify.toml
file.
We hope you found this overview of security headers to be helpful. You can find us on Twitter if you'd like to share your thoughts with us. We'd love to hear from you.
Want to read more tips and insights on working with a website development team that wants to help your organization grow for good? Sign up for our bimonthly newsletter.
Engineer
What happens when you cross years of study in biology and medicine with a degree in computer science? You get someone like Rachel.