Execution Timing
October 1, 2020
Measuring the time of JavaScript execution in a browser can give attackers information on when certain events are triggered, and how long some operations take.
Timing the Event Loop #
JavaScript’s concurrency model is based on a single-threaded event loop which means it can only run one task at a time. If, for example, some time-consuming task blocks the event loop, the user can perceive a freeze on a page as a result of the UI thread being starved. Other tasks must wait until the blocking task finishes. Each browser implements different process models, which means some web sites might run in different threads (and event loops) depending on their relations.
Some techniques can exploit this model to steal secrets from a cross-origin page:
- Inferring how long code from a different origin takes to run by measuring how long it takes to run next in the event pool 1 2. The attacker keeps sending events to the event loop with fixed properties, which will eventually be dispatched if the pool is empty. Other origins dispatch events to the same pool, and this is where an attacker infers the time difference by detecting if a delay occurred with one of its tasks.
- Stealing a secret from a cross-origin page if the said secret is being compared by an attacker-controlled string. The leak is a result of comparing time differences in the event loop of a char-by-char string comparison 2 (using the previous technique). In browsers without process isolation, cross-window communications between different origins run in the same thread, thus sharing the same event loop.
important
The latter attack is no longer possible in browsers with process isolation mechanisms in place. Such mechanisms are currently only present in Chromium-based browsers with Site Isolation; they are coming to Firefox soon under the name Project Fission.
Busy Event Loop #
Another technique used to measure JavaScript execution consists of blocking the event loop of a thread and timing how long it takes for the event loop to become available again. One of the main advantages of this technique is its ability to circumvent Site Isolation, as an attacker origin can influence the execution of another origin. The attack works as follows:
- Navigate the target website in a separate window with
window.open
or inside aniframe
(if Framing Protections are not in place). - Wait for the long computation to start.
- Load any same-site page inside an
iframe
, regardless of any Framing Protections.
An attacker can detect how long the target website is executed by timing how long it took for the iframe
(in step 3) to trigger the onload
event (Network Timing of step 3 should be minimal). Since both navigations occurred within the same context and they are same-site, they run in the same thread and share the same event loop (they can block each other).
// Open a new window to measure how long the window blocks the event loop
// for the site example.org
window.open('https://example.org/expensive');
// TODO: Wait for the expensive window to load, e.g. via timeout
// then create an iframe to the same site
var ifr = document.createElement('iframe');
ifr.src = "https://example.org";
document.body.appendChild(ifr);
// Measure the initial time
var start = performance.now();
ifr.onload = () => {
// When the iframe loads calculate the time difference
var time = performance.now() - start;
console.log('It took %d ms to load the window', time);
}
Service Workers #
Service Workers can be used to offer offline solutions to web applications, but they can be abused by attackers to measure the timing of JavaScript execution3. They serve as a proxy between the browser and the network and allow applications to intercept any network requests made by the main thread (document).
To make a timing measurement, an attacker can perform the following steps:
- The attacker registers a service worker in one of their domains (attacker.com).
- In the main document, the attacker issues a navigation (window.open) to the target website and instructs the Service Worker to start a timer.
- When the new window starts loading, the attacker navigates the reference obtained in step 2 to a page handled by the Service Worker.
- When the request performed in step 3 arrives at the service worker, it returns a 204 (No Content) response, which aborts the navigation.
- At this point, the Service Worker collects a measurement from the timer started in step 2. This measurement is affected by how long JavaScript blocked the navigation.
Since no navigation actually occurs, steps 3 to 5 can be repeated to obtain more measurements on successive JavaScript execution timings.
jQuery, CSS Selectors & Short-circuit Timing #
Attackers can abuse another interesting behavior of CSS selectors which is short-circuit
evaluation of expressions. This expression is received in a URL
hash and evaluated if the page executes jQuery(location.hash)
4.
A timing attack is possible because the expression is compared from right to left, so if the selector main[id='site-main']
does not match and fails to evaluate, the other parts of the selector (*:has(*:has(*:has(*))))
), which take longer to execute, are ignored (just like the and
operator, but backwards).
$("*:has(*:has(*:has(*)) *:has(*:has(*:has(*))) *:has(*:has(*:has(*)))) main[id='site-main']")
tip
In browsers with process isolation mechanisms, Service Workers can be abused to obtain the execution timing measurement or tricks like Busy Event Loop tricks can be used to circumvent Site Isolation.
ReDoS #
warning
This group of XS-Leaks requires an injection of Regex Expressions on the target page.
Regular Expression Denial of Service (ReDoS) is a technique which results in a Denial of Service in applications that allow regex as user input 2 5. Maliciously crafted regular expressions can be made to run in exponential time. This can be used as an XS-Leak vector if a regex can be injected that has a different runtime depending on the data on the page. This could happen on the client-side or the server-side.
Defense #
Attack Alternative | SameSite Cookies (Lax) | COOP | Framing Protections | Isolation Policies |
---|---|---|---|---|
T. Event Loop | ❌ | ❓ | ❌ | NIP |
Service Workers | ✔️ | ✔️ | ❌ | NIP |
jQuery | ✔️ | ❌ | ❌ | NIP |
ReDoS | ✔️ | ❌ | ❌ | NIP |
Busy Event Loop | ✔️ | ✔️ | ❌ | NIP |