Why can’t I set the font size of a visited link?
Visited links show up purple; unvisited links show up blue.
This distinction goes back to the beginning of the web.
But CSS allows you to customize this visual difference using the :visited
pseudo-selector!
Say you wanted to make visited links gray and smaller,
to indicate to the user that this link is “done”:
a:visited {
color: gray;
font-size: 6px;
}
This style is applied on this page, and here’s a sample:
Notice that the visited link appears gray, as expected,
but the font size hasn’t changed!
This is because changing the font size would be a security vulnerability!
If CSS could set the font size differently,
I (Jim) could tell whether you’ve visited pornhub.com
.
But how?
Web pages are able to inspect the rendered elements on the page.
The most obvious way is with window.getComputedStyle()
.
Here are the reported properties of the above visited link,
as reported by your browser:
.
If getComputedStyle
were to report 6px
instead of 18px
for visited links,
I could have this page generate a link to pornhub.com
,
then test its font size,
in order to reveal your browsing history.
I could then serve you targeted ads,
sell your data,
blackmail you,
et cetera.
This security hole has been plugged
by not allowing a:visited
to set the font-size
.
But notice what getComputedStyle
reported for the color of the visited link:
rgb(0, 0, 238)
, i.e., blue.
This is a lie - the link is gray!
For the color
property,
browsers have plugged the security hole in a different way:
instead of disallowing the property to be customized,
they have getComputedStyle
lie about its value.
Why two approaches?
Why can’t we have getComputedStyle
lie for font-size
, too?
The reason is that
web pages can inspect the rendered elements via more than getComputedStyle
.
Web pages can check an element’s position in the page,
via .pageXOffset
or .pageYOffset
.
Since font-size
of the visited link would affect the offset of other elements,
the page could indirectly check whether the link is visited.
Disabling font-size
for a:visited
is a brutal, but safer, solution.
There’s a short whitelist of properties that,
like color
,
shouldn’t affect page layout,
and so shouldn’t be detectable.
They’re all different forms of color.
All other CSS properties are banned.
In theory, there is no way that a web page can determine whether a link has been colored differently. One possibility is a timing attack: say, if it takes longer to color something pink compared to blue, the page could measure how long it took to render the element, and compared this to an expected duration.
This page copyright James Fisher 2019. Content is not associated with my employer.