2006-08-27

CSS Exploit

While this isn't exactly a security risk, I just read about a disturbing privacy exploit possible with CSS. The idea is that you can use the :visited property of a hyperlink in CSS to detect if someone has visited certain links on your website whether or not they click on the link from your website.

In other words, if you visit Google, and later visit a web page with this trick set up, the owner of the web page will know that you were in Google. There is a drawback (thankfully) that prevents this from being a total privacy disaster: the links have to be predefined on the web page. I.e. I can't just rip your browser history, but I can throw out some links and see if you've visited them recently. Also, http://google.com and http://www.google.com are seen differently, so the page has to include both.

Some sites (listed below) have set up examples of this trick, along with "how-to" code, so I'm going do the same. My example is a bit simpler, since I'm not doing anything with the data - I'm just going to dump a list of sites, putting the ones you have visited in bold, and crossing out the rest. If I want to actually do something with the data, I can use the getStyle function from the excellent site QuirksMode to see if the link is bold or not, and if it is, pass it along to some hidden script. This won't work outside the actual page (i.e. in an RSS reader or other aggregator).

So without further ado:


If you click on a crossed-out link and then come back to this page, the link should now be bolded. The CSS I use for this is really simple:

a.hack {display: block; text-decoration: line-through; font-weight: bold;}
a.hack:visited {text-decoration: none; font-weight: normal;}

To take this a step further and start doing something with this data, I can write some Javascript:

//uses slightly modified getStyle() (not shown) from
//http://www.quirksmode.org/dom/getstyles.html
var visited_sites = [];
for (var i=0; i < document.links.length; i++)
{
var link = document.links[i];
if (getStyle(link, 'text-decoration') == 'line-through')
continue;
visited_sites.push(link.href);
}

At the end of this code block, I have a list of links called visited_sites, which I can save on a server somewhere using AJAX, for example.

Here are the pages I adapted this technique from (they use slightly different approaches - either more CSS or more Javascript - I decided to spread the wealth and liked the result :-) )
  • milov.nl
  • Jeremiah Grossman (working example)
  • Browser Spy (most thorough example)
  • TechFoolery - where I first saw this mentioned. Also, interesting points in comments: it's old news in the security community, but apparently no one listens to security people...

    Anyway, if you're a privacy nut, you may want to look further into this... I don't think most people have to worry but I could be wrong.

    UPDATE: I just saw this link - apparently there are some security risks after all...

    --YY
  • No comments: