$ fingerprint@info:~ echo $VISIT-HISTORY
The :visited CSS pseudo-class represents links which the user has already visited. Visited links are displayed with a different color as not yet visited links, if the browsing history and visited-link highlighting is enabled in the browser. This may allow a better user experience for browser users who have their browsing history enabled. For more details see, e.g., MDN web docs
Visited-link highlighting is cross-site (no per-site visitation history). This means, regardless of which URL has been visited or which website is currently displayed,
all visited links in the browser history are highlighted via the :visited CSS pseudo-class, if a link from the browsing history
appears within an anchor tag on a website.
In the past (2006), this fact was exploited to query visited URLs from user histories (e.g., Bugzilla Ticket).
Jeremiah Grossman checked the color of a link
with the JavaScript method getComputedStyle to
detect if a specific URL is in the browser history. Several years later, this was fixed and the method getComputedStyle now
lies and will always return values indicating that a user has never visited any of the links on a page.
Paul Stone proposed a different technique to achieve the same goal without any
color readouts, but instead rely on a timing attack: Place a (large) number of anchor tags on the web page, with the href property set to a link for which it is known the visitor had not yet visited (long, fixed/random URL).
Then update all href properties to point to a URL for which it should be determined if the URL is in the browser history. The browser will then check if the URL is in the browser history.
If the tested URL is in the history, all anchor tags will be redrawn with the :visited CSS pseudo-class. If the URL is not present in the history, nothing happens (and no redraw will occur).
Therefore, the time it takes the browser to finalize after updating the href properties differs, if the test URL has been visited.
The timing attack is realized by using the JavaScript method requestAnimationFrame
to measure if redrawing happens.
The demonstration test "History stealing using timing attack" made by Antoine
Vastel reassembles this technique and works great for older Firefox versions (< 56), but does not work in Chrome and newer Firefox versions. As stated out in his article,
it should be kept in mind that errors can occur since the attack relies on time needed for a function to be executed.
The time may be influenced by external factors such as the fact that the browser is loading other pages which execute JavaScript.
In addition to this, it must be remarked that each browser (and version) behaves differently due to many reasons (JS engine, usage of system hardware and resources or size of the browser window, etc.) and the timing attack cannot
be
genaralized to optimal parameters that will work in every browser.
A modified version
by Xidorn Quan works in chrome, but still provides unreliable results.
In this demonstration, the original code was fine-tuned and a performance calibration test runs to reckon the number of links to be switched
and the criterion to compare test and baseline timings is adapted based on the timing results of performed requestAnimationFrame calls in the browser.
After this calibration test, either a message is shown that apparently history or visited-link highlighting is not enabled in the browser
or the actual history visit test starts with optimized parameters for the current browser.
The calibration runs lead to significant better detection results and broader support for different browsers and browser versions. Multiple runs yield reliable results,
if the system is not under heavy usage or the browser needs to process fast user interactions (scroll events).
Detailed explanation
The calibration phase starts with initial 500 links.
If the result for the test link, the location.href value (the current URL is always in browser history, if enabled),
yields 5 times in a row 'yes visited' or the ratio (multiplication factor derived from testcase and baseline timings) is greater than 7,
the test result is considered stable.
Then the test proceeds with actual link tests, where all test links need to fulfill a minimum of 60% of the original ratio rate of the stable calibration test.
Else, repeat the test with 500 additional links until a maximum of 3500 links (which means, 'visited links' is not available).
$ fingerprint@info:~ run visit-history-demo