How CSS can leak your browser history
The :visited pseudo-class
In addition to regular selectors for HTML tag name, ID, and class, CSS
also provides a few special selectors callde pseudo-classes. For
:hover pseudo-class represents an element that
the user is hovering over with their cursor.
This privacy-invading trick involves the
pseudo-class. It's a way to style links that the user has already
visited, making long lists of links easier to read.
The fact that the styling is based on your browser's history makes this pseudo-class an obvious security issue. Because of this, browsers implement a number of measures to make it difficult to exploit.
The only rules you can apply to visited links are
it's normally impossible to detect whether the rule is being applied
indow.getComputedStyle always acts
as if all links are unvisited.
If it weren't for these security measures, you could just include a
hidden link to
www.shady-site.com and then automatically
test whether the link has the visited style applied to it to figure out
if a user has gone to the shady site before.
So how can you exploit the
:visited pseudo-class when you
can't check if the style is being applied? Just trick the user into
Proof of concept
It's surprisingly easy to get people to give up their history with a little bit of trickery. I made a simple proof of concept that you can try out now. Don't worry, it only reports your history to you, check the source if you don't believe me.
The page simply assigns a common English word for each of the top 50
most visited sites in the US, and colors them black if the link is
:visited. Unvisited links are white and therefore
invisible, and a few decoy words are thrown in to make it less obvious
how it works. Then we just put an invisible
div over the
whole thing to prevent the user from clicking or selecting the links,
which would give away the trick.
This example is kind of silly, but it's not too hard to imagine implementing a CAPTCHA service that only shows certain letters if you've visited a particular site. In fact, Fräntz Miccoli has already implemented a demo that does exactly that.
How to protect yourself
These types of tricks are difficult to detect, so the best thing to do is just disable styling visited links entirely. You lose the benefit of seeing what links you've already clicked on some sites, but it makes you more secure.
In Firefox, just add this line to your
user.js file to
If there is a way to disable it in Chrome I couldn't find it, but you shouldn't really be using Chrome for security anyway.