Clocks

Clocks

October 1, 2020
Category Instrument

We can distinguish two types of clocks - Explicit and Implicit. Explicit clocks are the ones developers use to get direct timing measurements and such mechanisms are offered explicitly by the browser. Implicit clocks on the other hand, utilise particular web features to create unintended clocks that allow measuring the relative passage of time.

Explicit Clocks #

performance.now API #

The performance.now() API allows developers to get high-resolution timing measurements.

info

In order to mitigate some XS-Leaks, performance.now()’s accuracy was reduced from a range of nanoseconds to a microsecond precision in all modern browsers 1 2 3.


  1. Reduce resolution of performance.now (Webkit). link ↩︎

  2. Reduce precision of performance.now() to 20us (Gecko). link ↩︎

  3. Reduce resolution of performance.now to prevent timing attacks (Blink). link ↩︎

Date API #

The Date API is the oldest API present in browsers to obtain timing measurements. It allows developers to get dates, and get Unix timestamps with Date.now(). These measurements are much less precise than performance.now(). Before the introduction of newer APIs attacks used to leverage this instead 1.

Implicit Clocks #

SharedArrayBuffer and Web Workers #

With the introduction of Web Workers, new mechanisms to exchange data between threads were created 2. SharedArrayBuffer, one of those mechanisms, provides memory sharing between the main thread and a worker thread. Attackers can create an implicit clock by using two workers and a shared buffer. One worker runs in an infinite loop incrementing a number in the buffer. The other work can observe this number get incremented and use this to measure the relative passage of time.

// -------- Main Thread clock creation --------
var buffer = new SharedArrayBuffer(16);
var counter = new Worker("counter.js");
counter.postMessage([buffer],[buffer]);
var arr = new UintArray(buffer);
relative_time = arr[0];

// -------- Web Worker counter.js --------
self.onmessage = function(event){
  var[buffer] = event.data ;
  var arr = newUintArray(buffer);
  while(1){
    arr[0]++;
  }
}

important

SharedArrayBuffer was removed from browsers with the publication of Spectre. It was reintroduced later in 2020 requiring documents to be in a secure context to make use of the API. Since secure contexts cannot reference any cross-origin content that has not explicitly opted in to being accessed, this means SharedArrayBuffers cannot be used as clocks for XS-Leaks.

info

Since Firefox 79, this API can be used with full resolution in documents which do not share a browsing context group with cross-origin documents. This will require an application interested in this precision to explicitly opt-in to COOP and COEP.

Other Clocks #

There are a considerable number of APIs attackers can abuse to create implicit clocks: Broadcast Channel API, Message Channel API, requestAnimationFrame, setTimeout, CSS animations and others 3 4.

References #


  1. Exposing Private Information by Timing Web Applications, link ↩︎

  2. Shared memory: Side-channel information leaks, link ↩︎

  3. Fantastic Timers and Where to Find Them: High-Resolution Microarchitectural Attacks in JavaScript, link ↩︎

  4. Trusted Browsers for Uncertain Times, link ↩︎