How COOP and COEP Prevent Side-Channel Attacks
Cross-Origin Opener Policy (COOP) and Cross-Origin Embedder Policy
(COEP) are HTTP response headers that work together to place a web page
into a “cross-origin isolated” state. This article explains how these
mechanisms safeguard JavaScript memory by segregating browser processes
and preventing side-channel timing attacks, such as Spectre, while
allowing the safe use of powerful APIs like
SharedArrayBuffer and high-resolution timers.
The Threat: Side-Channel Timing Attacks
Side-channel timing attacks exploit microscopic variations in CPU execution times to read unauthorized data from memory. In web browsers, vulnerabilities like Spectre demonstrated that malicious JavaScript could measure memory access latency via CPU cache states to infer sensitive data belonging to other origins sharing the same rendering process.
To execute these attacks effectively, an attacker requires two
conditions: 1. Access to sensitive cross-origin data loaded into the
same process memory space. 2. High-precision timing capabilities (such
as SharedArrayBuffer or unthrottled
performance.now()) to measure microarchitectural cache hits
and misses.
Browsers initially mitigated this by reducing timer precision and
disabling SharedArrayBuffer. COOP and COEP provide a
structured mechanism to restore these capabilities securely by strictly
isolating process memory.
Cross-Origin Opener Policy (COOP)
The Cross-Origin-Opener-Policy header isolates top-level
documents from other windows. When a document specifies
Cross-Origin-Opener-Policy: same-origin, the browser
isolates the page in its own browsing context group.
This configuration prevents other websites that open your page—or
pages opened by your page—from interacting with its window object or
sharing execution processes. By severing the window.opener
reference across different origins, COOP ensures that unauthorized
external pages cannot access your page’s memory space via script
interactions.
Cross-Origin Embedder Policy (COEP)
While COOP secures top-level browsing contexts, documents often load
external subresources like images, scripts, stylesheets, and iframes.
The Cross-Origin-Embedder-Policy header restricts how these
resources are loaded into the page’s memory.
Setting Cross-Origin-Embedder-Policy: require-corp
forces the browser to block any cross-origin resource that does not
explicitly grant permission to be embedded. The resource must provide
either a Cross-Origin-Resource-Policy (CORP) header or
valid Cross-Origin Resource Sharing (CORS) headers. This stops unvetted,
sensitive cross-origin data from ever being loaded into the document’s
process memory.
Establishing Cross-Origin Isolation
When a server deploys both headers simultaneously:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
The browser grants the page cross-origin isolated
status (self.crossOriginIsolated === true).
In this state: * Process Boundary Enforcement: The
operating system and browser ensure the document executes in an isolated
process containing exclusively same-origin data and explicitly opted-in
resources. * Leak Prevention: Because no unvetted
cross-origin data resides in the process memory, there is no
cross-origin data available for a side-channel attack to read. *
API Restoration: Browsers can safely unlock
high-resolution timers and features like SharedArrayBuffer
and WebAssembly.Memory, as the timing mechanisms cannot be
used to leak data across origins.