44

Normally, the referrer is traceable through:

  • JavaScript's document.referrer
  • The request headers, e.g. PHP's $_SERVER['HTTP_REFERER']

I have set up a Codepad demo which shows these properties, for testing purposes.

#Requirements:

  1. The original referrer should effectively be hidden, at least for all mouse events.
  2. Cross-browser support (at least Chrome and Firefox).
  3. Stand-alone, without any external content (plugins, libraries, redirection pages, ...).
  4. No side-effects: Links should not be rewritten, history entries should be preserved.

The solution will be used to hide the referrer when following a link of <a href="url">.


##Exact description of the use-case As described in this question on Webapps, links at Google Search are modified on click. Consequently,

  1. Google is able to track your search behaviour (Privacy-- )
  2. The page request is slightly delayed.
  3. The linked page cannot track your Google search query (Privacy++ )
  4. Dragged/Copied URLs look like http://google.com/lotsoftrash?url=actualurl.

I'm developing a Userscript (Firefox) / Content script (Chrome) (code), which removes Google's link-mutilating event. As a result, points 1, 2 and 4 are dealt with.

Point 3 remains.

  • Chrome: <a rel="noreferrer">
  • Firefox: data-URIs. I have created a sophisticated approach to implement this feature for left- and middle-clicks, while still enforcing point 4. However, I'm struggling with the right-click method.
Community
  • 1
  • 1
Rob W
  • 341,306
  • 83
  • 791
  • 678
  • 6
    FWIW, Facebook redirect all external links to `l.php?the_url_you_want_to_visit`, to ensure no personal information is included in the referrer attribute. This *might* be a hint towards "it isn't possible". [Their detailed engineering note might be of interest.](https://www.facebook.com/notes/facebook-engineering/protecting-privacy-with-referrers/392382738919) – Matt Jan 17 '12 at 10:51
  • 4
    @Matt The reason that I want to not use external redirect pages is 1) Right-click copying will return the *redirect link* (instead of the *actual one*). 2) An external page is involved, which reduces the speed of browsing. See [this userscript](http://userscripts.org/scripts/show/121923). – Rob W Jan 17 '12 at 10:55
  • 1
    I think there is a better idea to break google's code's code which replaces plain links with their spyredirector – OnTheFly Jan 17 '12 at 11:13
  • @RobW What exactly do struggle with, concerning right-clicks? The "open in tab" context-menu entry? I'm pretty sure that requirement 4 makes that impossible to solve with a userscript. – user123444555621 Jan 20 '12 at 10:10
  • @Pumbaa80 On contextmenu: hide the referrer, but keep the original URL on copy. There are very few, if not none sources on the Internet for this problem. Some creativity is surely required to solve this problem. – Rob W Jan 20 '12 at 10:22
  • It's possible to keep on copy: http://jsfiddle.net/efa5Q/ (for some reason the copy command uses some special method). However the other context menu items like "save as...", "send" or "add bookmark" will recieve the data url. – user123444555621 Jan 20 '12 at 15:57
  • 1
    +1 -this is such an enduring question. whether used for good or *ad* [sic] this has so much merit and there are times when you just NEED to bypass the referrer (I have an instance just now where referring via my link produces the correct url, but then the base url detects this redirsct and issues it's own redirect back to my domain -not what i want. i'll try your solution and see if it works. however, the +1 remains either way as the logic here piqued my mind!! – jim tollan Sep 24 '14 at 20:38

10 Answers10

43

I have found a solution which works in Chrome and Firefox. I've implemented the code in a Userscript, Don't track me Google.

Demo (tested in Firefox 9 and Chrome 17): http://jsfiddle.net/RxHw5/

Referrer hiding for Webkit (Chrome, ..) and Firefox 37+ (33+*)

Webkit-based browsers (such as Chrome, Safari) support <a rel="noreferrer">spec.
Referrer hiding can fully be implemented by combining this method with two event listeners:

  • mousedown - On click, middle-click, right-click contextmenu, ...
  • keydown (Tab Tab Tab ... Enter).

Code:

function hideRefer(e) {
   var a = e.target;
   // The following line is used to deal with nested elements,
   //  such as: <a href="."> Stack <em>Overflow</em> </a>.
   if (a && a.tagName !== 'A') a = a.parentNode;
   if (a && a.tagName === 'A') {
      a.rel = 'noreferrer';
   }
}
window.addEventListener('mousedown', hideRefer, true);
window.addEventListener('keydown', hideRefer, true);

* rel=noreferrer is supported in Firefox since 33, but support was limited to in-page links. Referrers were still sent when the user opened the tab via the context menu. This bug was fixed in Firefox 37 [bug 1031264].

Referrer hiding for old Firefox versions

Firefox did not support rel="noreferrer" until version 33 `[bug 530396] (or 37, if you wish to hide the referrer for context menus as well).

A data-URI + <meta http-equiv=refresh> can be used to hide the referrer in Firefox (and IE). Implementing this feature is more complicated, but also requires two events:

  • click - On click, on middle-click, Enter
  • contextmenu - On right-click, Tab Tab ... Contextmenu

In Firefox, the click event is fired for each mouseup and hitting Enter on a link (or form control). The contextmenu event is required, because the click event fires too late for this case.

Based on data-URIs and split-second time-outs:
When the click event is triggered, the href attribute is temporarily replaced with a data-URI. The event finished, and the default behaviour occurs: Opening the data-URI, dependent on the target attribute and SHIFT/CTRL modifiers.
Meanwhile, the href attribute is restored to its original state.

When the contextmenu event is triggered, the link also changes for a split second.

  • The Open Link in ... options will open the data-URI.
  • The Copy Link location option refers to the restored, original URI.
  • ☹ The Bookmark option refers to the data-URI.
  • Save Link as points to the data-URI.

Code:

// Create a data-URI, redirection by <meta http-equiv=refresh content="0;url=..">
function doNotTrack(url) {
   // As short as possible. " can potentially break the <meta content> attribute,
   // # breaks the data-URI. So, escape both characters.
   var url = url.replace(/"/g,'%22').replace(/#/g,'%23');
   // In case the server does not respond, or if one wants to bookmark the page,
   //  also include an anchor. Strictly, only <meta ... > is needed.
   url = '<title>Redirect</title>'
       + '<a href="' +url+ '" style="color:blue">' +url+ '</a>'
       + '<meta http-equiv=refresh content="0;url=' +url+ '">';
   return 'data:text/html,' + url;
}
function hideRefer(e) {
   var a = e.target;
   if (a && a.tagName !== 'A') a = a.parentNode;
   if (a && a.tagName === 'A') {
      if (e.type == 'contextmenu' || e.button < 2) {
         var realHref = a.href; // Remember original URI
         // Replaces href attribute with data-URI
         a.href = doNotTrack(a.href);
         // Restore the URI, as soon as possible
         setTimeout(function() {a.href = realHref;}, 4);
      }
   }
}
document.addEventListener('click', hideRefer, true);
document.addEventListener('contextmenu', hideRefer, true);

Combining both methods

Unfortunately, there is no straightforward way to feature-detect this feature (let alone account for bugs). So you can either select the relevant code based on navigator.userAgent (i.e. UA-sniffing), or use one of the convoluted detection methods from How can I detect rel="noreferrer" support?.

Community
  • 1
  • 1
Rob W
  • 341,306
  • 83
  • 791
  • 678
  • Unfortunately, the data: URI couldn't be used in IE which supports it only for downloadable contents, not HTML. – Jakub Vrána Mar 20 '14 at 21:36
  • Middle-click with the event listener on the element (not the document) in Firefox 28 doesn't trigger hideRefer. Any ideas? – Jayen May 03 '14 at 11:44
  • Context menu with rel='noreferrer' (no javascript) doesn't hide the referrer on Chrome 34. Any ideas? – Jayen May 03 '14 at 12:28
  • I found https://code.google.com/p/chromium/issues/detail?id=87580 and http://code.google.com/p/chromium/issues/detail?id=345783 . Looks like a known bug in Chrome. – Jayen May 03 '14 at 12:34
  • userscripts.org is down. The alternative http://userscripts-mirror.org/scripts/review/181268 is a highjacked version. Where can the current release be accessed? – Lukas Jul 24 '14 at 11:56
  • 1
    @Lukas The web archive to the rescue: http://web.archive.org/web/20131105004231/http://userscripts.org/scripts/review/121923#root_footer – Rob W Jul 24 '14 at 11:58
  • 1
    The [bug 530396](https://bugzilla.mozilla.org/show_bug.cgi?id=530396) has been fixed. – Stephan Apr 02 '15 at 00:13
10

Can't you create a linking system that resides within iframes?

If you wrap an iframe around every link, the iframe can act as an external de-refer. The user would click on the link inside the frame, opening a page whose referrer is set to the iFrame's location, instead of the actual page.

Rob W
  • 341,306
  • 83
  • 791
  • 678
fmsf
  • 36,317
  • 49
  • 147
  • 195
  • 1
    I have just read your answer again. That's a nice idea. Can you elaborate your thoughts on setting a different URL of the iFrame, without using external pages? What about positioning the iFrame? – Rob W Jan 25 '12 at 16:26
  • 3
    I have awarded the bounty to your answer, because it contained a potentially useful concept, after tweaking. This method has some shortcomings/issues though. The main issue is the positioning and location of the frame. Using the `tab` key to navigate between links becomes more complicated as well. Finally, the performance hit/smoothness of dynamically adding frames over all anchors is also a subject of concern. – Rob W Jan 27 '12 at 14:04
  • 1
    [jpgerek](http://stackoverflow.com/users/311928/jpgerek) implemented the method described in this answer. See [this answer on this page](http://stackoverflow.com/questions/8893269/what-is-the-most-reliable-way-to-hide-spoof-the-referrer-in-javascript/12745307#12745307). – Rob W Oct 05 '12 at 13:07
6

As requested, by using JavaScript:

var meta = document.createElement('meta');
meta.name = "referrer";
meta.content = "no-referrer";
document.getElementsByTagName('head')[0].appendChild(meta);

This will add the following meta tag to head section of the web page:

<meta name="referrer" content="no-referrer" />

As of 2015 this is how you prevent sending the Referer header.

Marcelo Glasberg
  • 29,013
  • 23
  • 109
  • 133
3

There is a cross browser solution in Javascript that removes the referrer, it uses Iframes created dynamically, you can take a look to a proof of concept ( disclaimer: it uses a little JS library I wrote ).

jpgerek
  • 796
  • 1
  • 8
  • 13
  • 2
    Thanks for posting the implementation of the method described in [this answer](http://stackoverflow.com/questions/8893269/what-is-the-most-reliable-way-to-hide-spoof-the-referrer-in-javascript/8957865#8957865). It does **not work in Opera** (tested 11.62, 12.00b, 12.02) though. On the other hand, it does work in Safari 3+, Chrome 1+, Firefox 1+ and IE6, 7 and 8. It does **not work in Internet Explorer 9 and 10**. So, in practice, it's only useful in Chrome, Safari and Firefox. – Rob W Oct 05 '12 at 13:02
  • this link is dead – vir us Mar 26 '21 at 06:52
3

You could use the new Referrer Policy standard draft to prevent that the referer header is sent to the request origin. Example:

<meta name="referrer" content="none">

Although Chrome and Firefox have already implemented a draft version of the Referrer Policy, you should be careful with it because for example Chrome expects no-referrer instead of none (and I have also seen never somewhere). I don't know the behaviour if you just add three separate meta tags, but in case that does not work you could still just implement a short script which iterates over all three values and checks if the value was really set after setting the attribute/property of the meta tag.

This meta tag applies to all requests on the current page (ajax, images, scripts, other resources...) and navigation to another page.

Joel
  • 15,496
  • 7
  • 52
  • 40
1

A very comprehensive (but short) analysis can be found at:

http://lincolnloop.com/blog/2012/jun/27/referrer-blocking-hard/

this article analyses both methods explained in other answers (js method, iframe redirecting) and finally suggest a mediate redirector page approach, like the one seen in google search links.

Amir Ali Akbari
  • 5,973
  • 5
  • 35
  • 47
  • 1
    Thanks for the answer. Unfortunately, the blog only *mentions* the options. Besides, literally every possible solution in the blog post is already covered here: `rel="noreferrer"`, noreferrer on Github and iframe routing. The "Compromise usability" solution relies on creating an ugly redirect URL - exactly what I wanted to avoid. – Rob W Aug 26 '12 at 14:32
1

This is trickier than it might seem on first sight. Look at the code of this project:

https://github.com/knu/noreferrer

He promises quite what you want, but you have to do it on the linking page.

Boldewyn
  • 81,211
  • 44
  • 156
  • 212
  • Looked promising, originally. However, it's no more different than my own method (currently using data-urls+meta, `rel="noreferrer"`), except for the disabling of the middle-mouse method, which is not desired. I usually click through links using the scrollwheel. – Rob W Jan 17 '12 at 11:28
1

What you're asking for cannot be done in Firefox.

The current context menu implementation always passes the current document as a referrer:

// Open linked-to URL in a new window.
openLink: function () {
    var doc = this.target.ownerDocument;
    urlSecurityCheck(this.linkURL, doc.nodePrincipal);
    openLinkIn(this.linkURL, "window", {
        charset: doc.characterSet,
        referrerURI: doc.documentURIObject // <----------------
    });
},

// Open linked-to URL in a new tab.
openLinkInTab: function () {
    var doc = this.target.ownerDocument;
    urlSecurityCheck(this.linkURL, doc.nodePrincipal);
    openLinkIn(this.linkURL, "tab", {
        charset: doc.characterSet,
        referrerURI: doc.documentURIObject // <----------------
    });
},

// open URL in current tab
openLinkInCurrent: function () {
    var doc = this.target.ownerDocument;
    urlSecurityCheck(this.linkURL, doc.nodePrincipal);
    openLinkIn(this.linkURL, "current", {
        charset: doc.characterSet,
        referrerURI: doc.documentURIObject // <----------------
    });
}, 

Obviously, userscripts are not allowed to change the context menu implementation, so the only way out is a browser extension.

(Or, which would be a pretty poor hack, disable the context menu by calling preventDefault() on the contextmenu event, and use your own custom context menu)

user123444555621
  • 148,182
  • 27
  • 114
  • 126
  • The `openLinkIn` implementation can be found in [utilityOverlay.js](https://hg.mozilla.org/mozilla-central/file/7edc6c4cf83d/browser/base/content/utilityOverlay.js#l185) – user123444555621 Jan 20 '12 at 13:28
  • Actually, you have a very slim chance to trick the contextmenu, since the "copy to clipboard" command uses [a different method](https://hg.mozilla.org/mozilla-central/file/7edc6c4cf83d/layout/base/nsDocumentViewer.cpp#l2553) to get the URL, ignoring [`this.linkURL`](https://hg.mozilla.org/mozilla-central/file/7edc6c4cf83d/browser/base/content/nsContextMenu.js#l1204). – user123444555621 Jan 20 '12 at 14:11
  • Just digged through your linked resources. It seems not to be possible to implement a refferer-hiding feature without any side effects. If no-one else posts an alternative ,the bounty is yours. – Rob W Jan 21 '12 at 10:11
0

I have implemented a simple but effective iframe solution using jquery.

https://jsfiddle.net/skibulk/0oebphet/

(function($){
  var f = $('<iframe src="about:blank" style="display: none !important;">').appendTo('body');
  $('a[rel~=noreferrer]').click(function(event){
    var a = $(event.target.outerHTML);
    a.appendTo(f.contents().find('body'));
    a[0].click();
    return false;
  });
})(jQuery);
skibulk
  • 3,088
  • 1
  • 34
  • 42
-2

what if we submit a FORM using JavaScript, this way there will be no referrer.

document.form_name.submit()

basically we are submit a form with desired ACTION method.

highwingers
  • 1,649
  • 4
  • 21
  • 39
  • 1
    Doesn't work. visit http://jsfiddle.net/Bp52M/show/1/ ([source](http://jsfiddle.net/Bp52M/1) and type `document.referrer` in the console. You'll see that the referrer is still available. – Rob W Mar 28 '14 at 09:33