One of my recent tasks in Ginger was to ensure that we weren’t leaking referrer URLs when you click on an external link in Ginger. It seemed like an easy task and one that’s probably been solved before. What I found was a trainwreck of solutions and a classic example of the trade-off between security and usability.
The Problem
We use human-readable slugs in our URLs in Ginger. It makes it easy to identify where a link goes just by looking at it. It’s a win for usability. We also allow users to create links to external sites in the messages they create. Another usability win.
The problem is when a user clicks on one of these links, the URL from Ginger could be sent as the HTTP Referrer to the external site. This is bad for security and privacy. Those nice URLs could leak sensitive information and the risk would not be obvious to the user.
Possible Solutions
Does the browser handle it already?
The HTTP specs tell us:
Clients SHOULD NOT include a Referer header field in a (non-secure) HTTP request if the referring page was transferred with a secure protocol.
Ginger is only served via HTTPS, so any links to sites served via HTTP will not pass the referrer data. This decreases the risk quite a bit, but still leaves a vulnerability when somebody links from our HTTPS site to an external site using HTTPS as well.
Can we use the noreferrer
link type?
HTML5 appears to have an easy fix for this issue, the noreferrer
link type. Unfortunately, it’s only supported in Webkit browsers at the moment and the current version of Chrome still leaks data when you use the right-click context menu. Firefox has had a bug open for almost 3 years. I didn’t dig into Opera and IE.
Is there a quick JavaScript hack?
After hitting dead-ends on the standards, I started looking for a JavaScript workaround. There’s a noreferrer project on GitHub, but it fails when using the right-click context menu (Open in New Window, Open in New Tab) and introduces usability issues (middle-click is disabled, Opera gets sent through Google’s redirector). There’s a good StackOverflow discussion that proposes putting links inside an iframe or using data-URI links, unfortunately, the options are either flawed or so fragile that the user experience suffers.
Somebody else must have solved this. What are other sites doing?
I have a Basecamp account, so I checked it first. They don’t take any measures to hide the referrer data beyond using HTTPS as far as I can see. What about DuckDuckGo? They pride themselves on not providing tracking data. I ran some tests and things seemed to work really well (best I can tell, they are routing links through an anonimized iframe). Then I tried right-clicking and opening a link in a new tab. The referrer data leaked. Even people who’ve tried really hard aren’t covering all the bases!
Real Solutions
I came to the conclusion that we have two options:
Comprimise privacy
Take the Basecamp or DuckDuckGo route. We know it doesn’t cover all the edge-cases, but I don’t think our users would have a clue. I’m not excited about that option.
Comprimise usability
We could:
1. Remove all human-readable info from our URLs
2. Rewrite all the vulnerable URLs and send them through an anonymous redirector. Google does this and you end up with links like https://www.google.com/url?q=https%3A%2F%2Fgingerhq.com. It’s a jarring experience and provides unexpected results when bookmarking or copy/pasting via the context menu.
In the end, we need to prioritize our users’ security and privacy. We added the noreferrer
link type in hopes that it is better supported in the future and are sending all HTTPS links through our own anonymizer/redirector. If anybody has a better option, I’d love to hear it.
Notes
Thanks to Graham for helping me test solutions.
Note to self: Next time somebody asks why estimating software development projects is hard, point them to this article and explain it took the bulk of the day exploring dead-ends to come up with a solution.