Question

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.
Was it helpful?

Solution

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?.

OTHER TIPS

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.

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.

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 ).

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.

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.

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)

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.

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);

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top