SameSite Cookies

Element leaks

Some HTML Elements might be used to leak a portion of data to a cross-origin page. For example, the below media resources can leak information about its size, duration, type.

It’s possible to differentiate between media types via unique property for a given media type. For example, it is videoWidth for a <video>, or duration for an <audio>. The below snippet shows an example code that returns the type of a resource.

...

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.

...

Hybrid Timing

October 1, 2020

Hybrid Timing Attacks allow attackers to measure the sum of a group of factors that influence the final timing measurement. These factors include:

Some of the factors differ in value depending on the application. This means that Network Timing might be more significant for pages with more backend processing, while Execution Timing can be more significant in applications processing and displaying data within the browser. Attackers can also eliminate some of these factors to obtain more precise measurements. For example, an attacker could preload all of the subresources by embedding the page as an iframe (forcing the browser to cache the subresources) and then perform a second measurement, which excludes any delay introduced by the retrieval of those subresources.

...

ID Attribute

October 1, 2020

The id attribute is widely used to identify HTML elements. Unfortunately, cross-origin websites can determine whether a given id is set anywhere on a page by leveraging the focus event and URL fragments. If https://example.com/foo#bar is loaded, the browser attempts to scroll to the element with id="bar". This can be detected cross-origin by loading https://example.com/foo#bar in an iframe; if there is an element with id="bar", the focus event fires. The blur event can also be used for the same purpose 1.

...

Connection Pool

October 1, 2020

Another way to measure the network timing of a request consists of abusing the socket pool of a browser 1. Browsers use sockets to communicate with servers. As the operating system and the hardware it runs on have limited resources, browsers have to impose a limit. Run demo (Chrome) Run demo (Firefox)

To exploit the existence of this limit, attackers can:

  1. Check what the limit of the browser is, for example 256 global sockets for TCP and 6000 global sockets for UDP. 23
  2. Block \(255\) sockets for a long period of time by performing \(255\) requests to different hosts that simply hang the connection
// Client
for(let i=0; i<255; i++) fetch('https://'+i+'.example.com/', {mode: "no-cors", cache: "no-store"});
# Server
from http.server import BaseHTTPRequestHandler, HTTPServer
import time

class handler(BaseHTTPRequestHandler):
    def do_GET(self):
        time.sleep(float(100000))
        self.send_response(200)
        self.send_header('Cache-Control', 'no-store')
        self.end_headers()

with HTTPServer(('', 8000), handler) as server:
    server.serve_forever()
  1. Use the \(256^{th}\) socket by performing a request to the target page.
  2. Perform a \(257^{th}\) request to another host. Since all the sockets are being used (in steps 2 and 3), this request must wait until the pool receives an available socket. This waiting period provides the attacker with the network timing of the \(256^{th}\) socket, which belongs to the target page. This works because the \(255\) sockets in step 2 are still blocked, so if the pool received an available socket, it was caused by the release of the socket in step 3. The time to release the \(256^{th}\) socket is directly connected with the time taken to complete the request.
performance.clearResourceTimings();
await fetch(location.href, {cache: "no-store"});
await new Promise(r => setTimeout(r, 1000));
let data = performance.getEntries().pop();
let type = (data.connectStart === data.startTime) ? 'reused' : 'new';
console.log('Time spent: ' + data.duration + ' on ' + type + ' connection.');

Connection reuse #

With HTTP/1.1 (TCP) and HTTP/2 (TCP) and HTTP/3 (UDP) requests may reuse an existing connection for a host to improve performance. 45 HTTP/2 also has Connection Coalescing which allows different hostnames that are accessible from the same web server to reuse a connection. 6 This is currently keyed by if credentials are included in the request. Since a reused connection is normally faster this could allow for detecting if a site has connected to a host excluding anything that’s been cached and leaking information about the cross-site request by abusing Stream prioritization and HPACK compression. 7 Connections may get closed if they are left idle or the sockets are exhausted, for example 256 connections for HTTP/2 or 30 seconds idle for HTTP/3. 28 This may also leak when the connection happened and the browser can have per connection limits and on how many connections are allowed per host, for example 6 connections per host. 2

...