Ok we’re though with ETag based user tracking, now let’s see a slightly less effective but still usable ‘invisible’ user tracking method, the redirect based one.
First, the obligatory demo:
This is an iframe, it’s src is http://polar-hollows-5826.herokuapp.com/redirect/index/. As you can see on your developer toolbar/etc. that site does not set any cookie. Sometimes the iframe won’t load as Heroku has a new rule: free apps have to sleep multiple hours a day.
The trick is simple - browsers tend to cache HTTP 301 redirect codes, even if you restart the browser. But what is an HTTP redirect anyway? Well, it’s an HTTP server’s way of telling the browser that the document it requested can be found at another address. There are basically two types of redirects - permanent and temporary, HTTP status codes respectively 301 and 302. For this technique we use the 301 moved permanently response.
The timeline for a 301 redirect is as follows:
- The browser requests the document, http://funcats.lol/nyaancat.png
- The server knows that e.g. the document has been renamed to nyaancat-notsofunnyanymore.png, thus says 301 : location: /nyaancat-notsofunnyanymore.png
- The browser sees the response and now fires up another request to the new location http://funcats.lol/nyaancat-notsofunnyanymore.png
This all seems fine and innocent, but browsers cache 301 redirects (as they are meant to be permanent). This caching can be used like this:
- When the browser requests http://trackingserver.wow/trackmeplease.js for the first time, it gets redirected to e.g. http://trackingserver.wow/813bd2b9-6a5f-4314-b829-7e5dde8aa0ec/trackmeplease.js with 813bd2b9-6a5f-4314-b829-7e5dde8aa0ec being the newly generated userid. After this every request going to http://trackingserver.wow/trackmeplease.js automatically goes to http://trackingserver.wow/813bd2b9-6a5f-4314-b829-7e5dde8aa0ec/trackmeplease.js and this is all handled now in the browser (it cached the redirect target url), so the server gets the same userid it first generated.
Voilá, just like a sessionid coming from a cookie, with every request. This is what you can see in the iframe above.
Some proof of concept Django code (see the whole app at https://github.com/ochronus/poc-aspartame/ , including the example for ETag tracking, too):
def redirect(request, id=None):
The two templates:
The script (it simply puts the tracking id in the div, but in a real app it would send user action logs to the server):
I’ve tested this in IE, Safari, Chrome and Firefox.
A real reload (reload button or force-reload shortcut) usually flushes the cache and so does a browser cache flush - this is why it’s a weaker method than ETag based tracking, but for normal operation (in-page link clicking, etc.) this works just fine. This cache is also kept between browser restarts.
Pretty evil, but the real deal comes when you combine user tracking methods, like Evercookie does: http://samy.pl/evercookie/ - though it does not use this redirect technique.
Oh, I almost forgot: it’s unethical to track users without letting them know ;)