3
\$\begingroup\$

I've created a brief UserScript (GitHub repository) for TamperMonkey to stop Google from hijacking Search results URLs for tracking purposes when you click them:

// ==UserScript==
// @include     http*://www.google.*/*
// @run-at      document-start
// ==/UserScript==
(function () {
    'use strict';
    function handleNodes(nodes) {
        for (var i = 0, j = nodes.length; i < j; i++) {
            handleNode(nodes[i]);
        }
    }
    function handleNode(node) {
        if (node.tagName === 'A' && node.onmousedown) {
            node.onmousedown = null;
        }
        handleNodes(node.childNodes);
    }
    document.onclick = null;
    var observer = new MutationObserver(function (mutations, observer) {
        for (var i = 0, j = mutations.length; i < j; i++) {
            var mutation = mutations[i];
            for (var k = 0, l = mutation.addedNodes.length; k < l; k++) {
                handleNode(mutation.addedNodes[k]);
            }
        }
    });
    observer.observe(document, { childList: true, subtree: true });
} ());

The script seems to work for both Google "Classic" and Google Instant doing its job.

Since I'm not a UserScript or DOM guru I'd like some feedback on it. Did I make any mistake or inefficiency? Is there something that can be improved?

\$\endgroup\$
2
  • \$\begingroup\$ What sort of tracking are you looking to prevent? I mean, what does google track when you click on a link via onmousedown? I'm pretty sure the majority of their tracking is in their outbound links via href, which you cannot circumvent, even if you were to remove onmousedown (you can verify this by looking at their a tags in search results). \$\endgroup\$
    – Dan
    Commented Feb 2, 2016 at 13:30
  • \$\begingroup\$ @DanPantry I don't understand your href part: when I execute a search the results' <a /> have the correct hrefs, they get modified through JavaScript's onmousedown event handler set on the <a />; so if you remove the onmousedown event no URL hijack takes place (and then you can copy the result URL by right clicking it too!). See [i.sstatic.net/biEQd.png] \$\endgroup\$
    – Albireo
    Commented Feb 2, 2016 at 13:41

1 Answer 1

1
\$\begingroup\$

to stop Google from hijacking Search results URLs for tracking purposes when you click them

Wrong, there's a lot of ways websites profile you. One other method is your device fingerprint, the combination of hardware, software and network information that normally gets sent to the server. A server can then compute a hash and link it to you.

No matter how you block the click-jacked search results, if you end up on a page that happens to have some widget that reports back to their server (with the same hardware, software and network info), consider yourself tracked. These "widgets" come in a variety of forms, like ads, like buttons, tweet buttons, follow buttons etc.

As for your code...

node.onmousedown = null

You are only removing the inline/property handler. You're not preventing handlers that are assigned via addEventListener and delegated (handlers assigned to ancestors to listen to a descendant).

function foo(message){
  alert('No stopping ' + message);
}

var link = document.querySelector('a');

// Assigned as a property
link.onmousedown = function(){
  foo('property');
};

// Assigned as listener
link.addEventListener('mousedown', function(){
  foo('handler');
});

// Body property
document.body.onmousedown = function(){
  foo('delegated property');
};

// Delegated handler
document.body.addEventListener('mousedown', function(){
  foo('delegated handler');
});

// Your script only does this:
link.onmousedown = null;
<a href="#foo" onmousedown="foo('inline')">Test</a>

Now there's several steps needed to prevent it.

First, we cannot prevent addEventListener handles since removeEventListener requires the reference of the handle function which we normally don't have access to. The best we could do is to clone the node, which doesn't copy over handlers assigned via addEventListener.

Then we override the inline onmousedown by defining your own function. Then we prevent delegated handlers by calling stopPropagation.

Lastly, we replace the original element with the clone.

function foo(message){
  alert('No stopping ' + message);
}

var link = document.querySelector('a');

// Assigned as a property
link.onmousedown = function(){
  foo('property');
};

// Assigned as listener
link.addEventListener('mousedown', function(){
  foo('handler');
});

// Body property
document.body.onmousedown = function(){
  foo('delegated property');
};

// Delegated handler
document.body.addEventListener('mousedown', function(){
  foo('delegated handler');
});

var clone = link.cloneNode(true);

clone.onmousedown = function(event){
  event.stopPropagation();
}

link.parentNode.replaceChild(clone, link);
<a href="#foo" onmousedown="foo('inline')">Test</a>

\$\endgroup\$
1
  • \$\begingroup\$ Wrong, there's a lot of ways […] and link it to you. Yes, but that's not what's happening now (after you remove the clickjack). No matter how […] follow buttons etc. Undoubtedly, but that's not in scope of my question (to prevent these I use other means, e.g. uBlock Origin, session clearing on browser close, etc.). Thanks for the clone & replace idea, I'll try to implement it in my script. \$\endgroup\$
    – Albireo
    Commented Feb 3, 2016 at 8:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.