Security Tip: Is Your Referrer Leaking Information?
[Tip #81] Do you know what information is being leaked by the Referer header when your users click on external links?
The Referer
header is sent as part of an HTTP request to indicate where the request originated. This is useful for requests within your application to track how the user is moving between pages, as well as for requests between different sites for analytics - so you can see which sites are sending the most traffic your way.
Referer
was actually a misspelling of the word Referrer
, which was accidently used in the original proposal for the header. Some 0ther headers use Referrer
, just to confuse you!While passing around referrer information inside your app is incredibly useful, it can quickly become a security risk when it's passed outside your application onto third party sites.
For example, here's the top referrers list from Securing Laravel's Fathom Analytics:
You'll notice most are unknown, however, under that list we've got some familiar faces! (Including LinkedIn, surprisingly!)
If I keep looking down the referrers list, I'll come across some referrers that look like this:
intranet.somecompany.com
secure.corp.enterprise.com
scratchpad.person.com
do-not-share.secret.abc1232.company.com
These are all private apps that are broadcasting their existence out to the world!
If I had malicious intentions, I could use this list to form a list of targets, start conducting recon, and ultimately try to compromise each site. Some would be publicly accessible, either behind a password login (credential stuffing time!), or just open to the world and relying on an obscure domain. Others would be internal, but knowing the domain name opens up the possibility for a CSRF attack, etc.
How do we stop leaking referrer information?
This is where the Referrer-Policy
header comes in. It controls what information is sent in the Referer
header during HTTP requests, and you can use it to control how much (or little) is sent in each request.
Here are the main options you need to care about:
Referrer-Policy: strict-origin-when-cross-origin
Note, this is currently the default when you don't have a Referrer-Policy
set.
Internal requests will send the full URL, i.e. https://securinglaravel.com/security-tip-are-your-refer/?query=string
, while external requests will only send the protocol and domain, i.e. https://securinglaravel.com
, but only if it's not going to HTTP from HTTPS.
Use this to broadcast your site's domain, but not the full path or query string to external sites.
Referrer-Policy: no-referrer-when-downgrade
Send the full URL, i.e. https://securinglaravel.com/security-tip-are-your-refer/?query=string
, on all internal and external requests, unless it's going from HTTPS to HTTP.
Use this to broadcast the full originating path to external sites. This is the setting Securing Laravel uses to broadcast which article the user originated from.
Note, this can leak sensitive information, such as hashes and signatures in URLs. So ensure you only enable this on pages where URLs can be public knowledge.
Referrer-Policy: same-origin
Only send the full URL, i.e. https://securinglaravel.com/security-tip-are-your-refer/?query=string
, on internal requests. The referrer will not be included on any external requests.
Use this to prevent the Referer
header from leaking any information about your site, such as on internal or private pages.
I've only covered those three, but there are a number of other options which you might need in specific situations. Here's the full list:
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
To learn more about how they work, head over to the mdn web docs.