Everything you could ever want to know (and more) about controlling the Referer header

Technical

This is a technical post, intended as a useful resource for other implementors of security-conscious web apps. Regular FastMail users may find it of interest, but may safely ignore it; there are no changes to your FastMail account or email software.

What is the Referer header

The Referer header dates back to the beginning of HTTP and has the dubious honour of being the only header standardised with a misspelt name. The HTTP spec describes it like this:

The Referer[sic] request-header field allows the client to specify,
for the server's benefit, the address (URI) of the resource from
which the Request-URI was obtained (the "referrer", although the
header field is misspelled.) The Referer request-header allows a
server to generate lists of back-links to resources for interest,
logging, optimized caching, etc. It also allows obsolete or mistyped
links to be traced for maintenance.

There are many legitimate use cases, such as finding broken links on your site, tracing errors, or finding which search terms people Google to get to your homepage. It can also be used to enhance security: checking the Referer header is one method of stopping cross-site request forgery.

However, sometimes it's important for a site to be able to restrict the referrer leaking out due to privacy or security concerns. For example, we try to keep our URLs pretty clean and readable in the FastMail web app, but this means sometimes they may contain semi-private information you don't want to leak. For example, if you were contemplating a surprise acquisition of ACME Inc, you may have a folder dedicated to your correspondence called something like "ACME Inc Acquisition", and if you were to open a conversation in the folder, the URL would be:

https://www.fastmail.com/mail/ACME_Inc_Acquisition/{threadId}-{messageId}

Suppose you click a link in one of your emails that goes to ACME Inc's website – if the referrer were to be leaked, the website's logs would now show that someone had a folder called "ACME Inc Acquisition" (if anyone bothered to look). Not a huge leak, but still one we would prefer to avoid.

From a security perspective, "secret" URLs are often used these days to authenticate access to content. The URL contains a random or cryptographically signed token so that it cannot be guessed, but if you know the URL you can access the content. For example, many services that host user files (such as attachments) put these on a different domain to isolate them from the main service. This means, by design, that any authentication cookies are not sent, so a secret URL is often used instead to ensure only the legitimate owner can access the content. However, if the user follows a link in the attachment to another website, that site could now use the Referer header to download the attachment it was linked from, even though this is meant to be private.

So if you have a situation where for good privacy or security reasons a site wants to remove the Referer header, how can this be done?

HTML5 added a whole bunch of useful new values for the rel attribute, one of which is noreferrer (yes, spelt correctly this time). When this attribute is added, the browser is instructed not to set the header if the user follows the link. Support for this was first added to WebKit (Chrome/Safari) way back in 2009, arrived in Firefox in late 2014 and most recently was added to Microsoft Edge (but is not supported in any version of Internet Explorer).

This means that if your site is mainly used by people with up-to-date browsers, this is now widely supported. For older browsers, you can fall back to the slightly hacky technique of opening a new tab with JavaScript, then writing a refresh tag to load the actual url you want in the tab:

var newWindow = window.open( '', '_blank' );
newWindow.document.write(
    '<META HTTP-EQUIV="refresh" content="0; url=' + url + '">'
);

This will also remove the referrer (but does force you to open the link in a new tab).

Removing the referrer for every link on the page

Applying policy on a link-by-link basis can be useful, but it is easy to miss one, and not always practical depending on how the page is generated. In many situations you would rather apply a policy to the whole page. This is where we get more bleeding edge.

The "living HTML spec" has introduced a new <meta name="referrer"> tag that can be added to a page to set a universal policy, with a flexible set of semantics. The values you can use for this are found in the Referrer Policy specification, which is currently a W3C working draft. There's a lot more flexibility in the policies supported by this spec, including same-origin (the referrer is only sent when the link is to another page on the same domain) and origin-when-cross-origin (when making cross-domain requests, only the domain is sent as the referrer; the path is omitted).

According to the spec, you can also set the policy via a Referrer-Policy header, which is much more useful than a tag (for example when returning 3rd party content that you do not wish to modify) and more in line with other security measures of a similar nature, which are normally configured via HTTP headers.

However, although the (very useful, and usually correct) Can I Use site lists full support in the latest Chrome and Firefox, our testing seems to show this only applies to the much less useful meta tag delivery option, not the header. Probably their data is out of sync with the latest changes in the spec. Edge and Safari also only support the meta tag, but an older draft of the specification with much more limited policy values.

The story doesn't end there though. Referrer policy can also be configured via a Content-Security-Policy (CSP) header. Confusingly, this is defined in version 1.1 of the spec but does not appear in versions 2 or 3. We can only presume it has been deprecated due to the new (as yet unsupported) Referrer-Policy header. The allowed policies in CSP 1.1 match those of the older <meta> policy spec, which is consistent with this theory. Confusingly again, the values are not single-quoted, unlike other keywords in CSP such as 'self'. Can I Use only lists implementation support for v1.0 and v2.0, and there doesn't seem to be any other comprehensive documentation on support out there, but our testing again shows support in recent Chrome/Opera/Firefox, but not in Edge/Safari.

As an aside, it seems odd to us that the policy wasn't developed as a header from the start, given its advantages over the <meta> tag (in fact it's strictly more useful, as you can always use an http-equiv meta tag to insert the value of the header that way too).

Anyway, it looks like finally the browsers are implementing a serious solution to this important security issue, but the current situation for developers is less than ideal. Using rel=noreferrer on each link has widespread support. Use of a <meta name="referrer"> tag has wide support for an out-of-date spec, and if neither of these are options then a Content-Security-Policy header will work for a good proportion of users, but not everyone; whether this is sufficient is a judgement you will have to make based on the security model for your app. Still, knowing your options is an important first step!