By Rachel Opperman
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: DENYWhen the header is given a value of DENY, the page cannot be displayed in a frame.
X-Frame-Options: SAMEORIGINWhen 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: nosniffThis configuration will block a request if the request destination is of type:
styleand MIME type is nottext/cssscriptand 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: onA value of on will enable DNS prefetching, which is the default browser behavior if the header isn't present.
X-DNS-Prefetch-Control: offA 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>; includeSubdomainsSpecifying 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-referrerProviding 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-downgradeThis 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: originWith a value of origin, the Referer header will include the origin but not the path.
Referrer-Policy: origin-when-cross-originIn 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-originSpecifying 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-originWith 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-originLike 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-urlFinally, 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.
Looking for a web development partner? Zaengle is the preferred development team for a number of businesses and organizations, large and small. We'd love to connect and see how we can help you.
By Rachel Opperman
Engineer
What happens when you cross years of study in biology and medicine with a degree in computer science? You get someone like Rachel.