13

I want to hide the referrer when I click a link on my website. To understand better what I want to do: When somebody clicks a link on my website, I don't want the other website owner to know where the visitor came from.

I don't care if it's done by PHP, HTML or Javascript.

I tried with HTML refresh, javascript window.location, javascript popup, PHP header redirect, but nothing worked.

Alex
  • 4,674
  • 5
  • 38
  • 59
  • WOW. You're being really useful. I've tried them all with no success. – Alex Jun 21 '11 at 16:36
  • 1
    What exactly did you try when you say `PHP header redirect`? Can you show us the code? `header('Location:' /* ... */);` normally does the trick, so I'm confused why your case doesn't. – pinkgothic Jun 21 '11 at 16:39
  • That would work, but how do I trigger the "header" by a click ? I tried doing this: a.php has the links. When you click the b.php?url=google.com link, b.php uses php header to redirect to google.com. But google.com sees you coming from a.php. If i visit b.php?url=google.com directly, no referrer will be sent. – Alex Jun 21 '11 at 16:44
  • 1
    Your `b.php` should have the `header()` call. The `3XX` status code (implicitly set by PHP when you call `header('Location: ' /* ... */);`) response *should* make your browser redirect and not send a referer. What browser are you using that the referer is still sent? – pinkgothic Jun 21 '11 at 16:47
  • 1
    @pinkgothic: He wants to outsmart the browser so that all HTTP requests initiated by clicking outgoing links on his website would have their *Referrer* header removed. – Saul Jun 21 '11 at 16:56
  • I am using Google Chrome. I noticed that other browsers can be tricked easily not to send the referrer, but this one sends it whatever I do. – Alex Jun 21 '11 at 16:59
  • 1
    @Saul: Yes, I'm aware - that should do it. Though maybe it's only consistent throughout browsers if your dereferer is a `HTTPS` dereferer. / Edit: @Alex Dumitru: Interesting. I'll have to take a look at that. Thanks for the info. – pinkgothic Jun 21 '11 at 16:59
  • 2
    @Alex Dumitru: Just a heads-up, it does seem to be a `HTTPS`/`HTTP` difference. Using Chrome and jimp's answer on an `HTTPS` server sends no referer. If you say your solutions like it do for `HTTP`, that's your difference. Is HTTPS an option for you? – pinkgothic Jun 21 '11 at 17:05
  • I knew about HTTPS and yes, it does work, but it's not an option, unfortunately :( – Alex Jun 21 '11 at 17:07
  • That's a shame. Then I'm out of advice, unfortunately. Good luck! – pinkgothic Jun 21 '11 at 17:09
  • 1
    I've created a reliable referrer-hiding method for Chrome and Firefox, see **[What is the most reliable way to hide / spoof the referrer in JavaScript?](http://stackoverflow.com/a/8957778/938089?what-is-the-most-reliable-way-to-hide-spoof-the-referrer-in-javascript)**. – Rob W Feb 04 '12 at 11:47
  • Here is a simple javascript/iframe trick that works on all current browsers if using https: http://stackoverflow.com/a/30304058/2440 – Sire May 18 '15 at 13:17
  • I've been using [Hide Referrer](https://hidemyreferrer.com/) for months now without any issues. It works on HTTP & HTTPS URL's + it's free to use. – Brian Smith May 31 '17 at 15:57

8 Answers8

22

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

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

Just add this to the head section of the web page. Works both for links and for Ajax requests.

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

In HTML 5 links should support rel="noreferrer" for this purpose.

H.B.
  • 166,899
  • 29
  • 327
  • 400
9

Here is a fool proof way to do this. I use this script in an app that sometimes links to 3rd-party websites from pages who's URLs need to be kept private.

<?php
session_start();

/**
  Setp 1. Get the query string variable and set it in a session, then remove it from the URL.
*/
if (isset($_GET['to']) && !isset($_SESSION['to'])) {
    $_SESSION['to'] = urldecode($_GET['to']);
    header('Location: http://yoursite.com/path/to/this-script.php');// Must be THIS script
    exit();
}


/**
  Step 2. The page has now been reloaded, replacing the original referer with  what ever this script is called.
  Make sure the session variable is set and the query string has been removed, then redirect to the intended location.
*/
if (!isset($_GET['to']) && isset($_SESSION['to'])) {
    $output = '<!DOCTYPE html>
<html>
<head>
<meta name="robots" content="none">
<title>Referral Mask</title>
</head>
<body>
<h3>Redirecting...</h3>
<script>window.location.href="'.$_SESSION['to'].'"</script>
<a href="'.$_SESSION['to'].'">Here is your link</a>
</body>
</html>' . "\n";
    unset($_SESSION['to']);
    echo $output;
    exit();
}
?>
<!DOCTYPE html>
<html>
<head>
<meta name="robots" content="none">
<title>Referral Mask</title>
</head>
<body>
<h1>Referral Mask</h1>
<p>This resource is used to change the HTTP Referral header of a link clicked from within our secure pages.</p>
</body>
</html>

This script uses both PHP and JavaScript to reliably remove the original referrer from the headers.

honyovk
  • 2,717
  • 18
  • 26
  • Does not work any more, at least in Firefox, quite infuriating. – H.B. Feb 18 '16 at 10:11
  • @H.B. Keep in mind this answer was written in 2012... What about it does not work? Is it a PHP error on the server, or a JavaScript error in the browser? – honyovk Feb 22 '16 at 20:25
  • Nothing of the sort. The browser simply sets the referrer header when changing the location via `location.href` now. One thing that now can be done when adding links that should be anonymous is setting `rel="noreferrer"` on the links though. – H.B. Feb 22 '16 at 21:01
3

Work-around, not a solution:

generate all such links through tinyurl.com or similar service.

Take <url> you want to redirect to, and raw-url-encode it. Generate some random string of say 10-15 chars (to ensure it's availability) lest call it <alias>.

Then call http://tinyurl.com/create.php?alias=<alias>&url=<url>

E.g. http://tinyurl.com/create.php?alias=ahdiwabdoubiadasd&url=http%3A%2F%2Fwww.whatismyreferer.com%2F

Now you can verify that http://tinyurl.com/ahdiwabdoubiadasd leads to www.whatismyreferer.com with referrer disguised

mkilmanas
  • 3,395
  • 17
  • 27
2

Updated code:

This code is a proof of concept only. Navigation away from the parent page is cancelled and the target url is messaged to an iframe. The iframe loads a dara url, which counts as a "null" origin document. When the frame receives the message, it redirects the user to the target url with a "null" referrer. Since the frame has a null origin, it cannot be messaged directly. As a result, another web page could potentially intercept the message via their own anonymous iframe. In production, you should still use rel="noreferrer" on your links, in case your users have disabled javascript, or a javascript error occurs on your page. In the case of old browsers with JS disabled, the referrer could still be exposed. This example may only be loaded after the body of the web page, so any clicks before the page has fully loaded may not be processed by the script.

An improved workflow would include generating an encryption key, adding it inside the iframe, encrypting the target url before messaging it, then decrypting it inside the iframe. That way you wouldn't need to worry about third-party snooping.

(function($) {

  var frame = $('<iframe sandbox="allow-scripts allow-top-navigation" src="data:text/html;charset=utf-8,<scr\ipt>window.addEventListener(\'message\', function(event){ if(event.origin == \'' + window.origin + '\') top.window.location = event.data; });</scr\ipt>" style="displayyyy: none !important;">').appendTo('body');

  $('a').click(function(event) {

    frame[0].contentWindow.postMessage( event.target.href, '*' );
    return false;

  });

})(jQuery);

Original post:

Here's my attempt at a fallback solution using a blank iframe. I haven't gotten it to work, but I'm sharing it in case anybody else want to fiddle with it. Technically the frame is cross-origin, so you can't just click a link in the frame. My thought was to use postMessage to make the frame click itself.

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

(function($){

  var frame = $('<iframe src="about:blank" style="displayyyy: none !important;">').appendTo('body');

  $('a[rel~=noreferrer]').click(function(event){

    var win = frame[0].contentWindow;
    win.$ = $;

    frame
    .contents()
    .find('body')
    .append(event.target.outerHTML)
    .append( "<scr\ipt> window.addEventListener('message', function(event){ document.append(event.data); $('a').click(); }); </scr\ipt>" );

    win.postMessage('Hi','*');
    return false;

  });

})(jQuery);
skibulk
  • 3,088
  • 1
  • 34
  • 42
2

In addition to jimps' answer i created a one file .php solution that will work with both HTTPS and HTTP. It uses two steps (and so it will call anonym.php twice). First a javascript redirect, second a php header location redirect. I personally needed this to test posted urls from within an admin area. Enjoy!

<?php
  // anonym.php

  if ($_SERVER['QUERY_STRING']) {

    if (stripos($_SERVER['QUERY_STRING'], 'anonym2=') === FALSE) {
      echo '<script>document.location.replace("anonym.php?anonym2=' .$_SERVER['QUERY_STRING']. '");</script>';
    } else {
      header('Location: ' . str_replace('anonym2=', '', $_SERVER['QUERY_STRING']));
    }

    exit();

  }

?>

In adition to

1

You could make all your links pass through a proxy redirection or link-shortening service (e.g. bit.ly or goo.gl), but that may raise some eyebrows among users.

You could also (again, not advisable) replace your hyperlinks with ones which trigger a server-side postback and programmatically 'construct' the headers before sending the request off.

All a bit overkill though, in my opinion.

Widor
  • 13,003
  • 7
  • 42
  • 64
  • Unfortunately bit.ly, goo.gl and the other link-shortners do not hide the referrer. I don't really understand how to do the second part. Could you please explain it a bit ? – Alex Jun 21 '11 at 16:38
  • 2
    iirc bit.ly & most shorteners will pass on referrer information, something like anonym.to will not – Alex K. Jun 21 '11 at 16:39
  • 2
    anonym.to and other anonymizers will change the referrer, but not hide it at all. For example the referrer for anonym.to will be like anonym.to/?http://www.google.com – Alex Jun 21 '11 at 16:40
  • 1
    @Alex Dumitru: Hmm, why does it concern you if `anonym.to` is in the referer, as long as your site isn't? Just to understand your use case better. – pinkgothic Jun 21 '11 at 16:44
  • I want no referrer to be sent. It must be blank like if you visited the site directly by typing it in the browser. – Alex Jun 21 '11 at 16:45
  • Sorry, bad examples in that case! There are ones which hide it, just have a look around. The second part is out of my depth when using PHP, as I've only done similar header manipulation in ASP.NET. – Widor Jun 21 '11 at 16:46
  • @Alex Dumitru: Well, yes, I gather that. :) It's more that I'm curious about *why* - I just honestly don't understand the motivation, and would like to, if it's okay to ask. Usually people just don't want *their* website URLs leaking. – pinkgothic Jun 21 '11 at 16:51
  • @Widor: When talking to a browser, the server can't respond with a request. Redirect is a response whereas *Referrer* can only appear inside a request which, in this scenario, is always constructed by the browser. – Saul Jun 21 '11 at 16:52
  • @Saul Yes, you're right of course. My scenario was fetching other sites from server-side. – Widor Jun 21 '11 at 16:58
-3

We use a simple script we developed in-house for an internal task system. We don't want referrer information passed either! When I watch other websites we manage, I do not see any referrer information passed with the request when using the script, but without the script I do.

<?php
// anonym.to.php
// Redirect URLs so the referrer information is dropped. Ideally, this script would be 
// invoked by prefixing all external links like this: "/anonym.to.php?URL"

// If a query string is given, then assume it is a website
// and anonymously redirect to it.
        if ($_SERVER['QUERY_STRING'])
        {
                header('Location: '.$_SERVER['QUERY_STRING']);
                exit(0);
        }
?>
jimp
  • 16,999
  • 3
  • 27
  • 36
  • 2
    This doesn't work on Chrome. The referrer is still send. Please check and let me know if I'm right or maybe I didn't do it right. – Alex Jun 21 '11 at 17:02
  • 3
    It works in Chrome, but we are using HTTPS. I noticed your comments with @pinkgothic above, and I can confirm what he was saying. This trick apparently works for HTTPS, but not for HTTP. I have tried Chrome 12 and Firefox 4. It doesn't matter if the "anonym.to" script uses HTTPS, it only matters if the page with the initial click is using HTTPS. I haven't tracked the spec down, but I suspect HTTPS requires referrer information to be dropped across a Location: redirect. Perhaps some tweaking with additional redirects might work, i.e., more redirection hops, I'm not sure. – jimp Jun 21 '11 at 17:27