chromium/services/network/public/cpp/orb/README.md

# Cross-Origin Read Blocking / Opaque Resource Blocking (CORB/ORB)

tl;dr:

* CORB and ORB are related solutions to the same problem.
* One can consider CORB to be v1, and ORB to be v2.
* This directory implements both.
* Implementation and rollout will be in stages.
* For websites that correctly label the MIME types of their responses none of
  this matters.

# The Problem CORB/ORB Are Solving

Browsers enforce the [same-origin policy](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy)
for many website-initiated fetches. However, in some contexts, the same origin
policy does not apply. For example, a page may load images from other origins.
The specification refers to these as requests with a ["no-cors" request mode](https://fetch.spec.whatwg.org/#concept-request-mode).

Meanwhile, the ["Spectre" family of attacks](https://chromium.googlesource.com/chromium/src/+/main/docs/security/side-channel-threat-model.md)
allow a website to read memory within an operating system process.
(Caveats apply and it's more complicated that that; but that's the gist.)

These, at its extreme, allow a near-complete circumvention of the "same-origin
policy": By first loading any resource one wishes to read via e.g. an `<img>`
tag, and then reading the result from its own memory via a "Spectre" gadget.
In this scenario, the image loading will fail and the site does not get
any programmatic access to the image content. (That is, to the bytes of the
resource, that the attacker pretended to be an image.) But because the
"image" has been brought into the renderer process (in order to parse it), and
because "Spectre" allows access to memory within the process, an attacking
page might get its contents after all.

Additionally, CORB/ORB serve as a "defense in depth" measure: They help
to improve [isolation](https://chromium.googlesource.com/chromium/src/+/main/docs/process_model_and_site_isolation.md) between origins and thus make it
harder [to exploit a compromised renderer](https://chromium.googlesource.com/chromium/src/+/main/docs/security/compromised-renderers.md).

## Security Properties

In brief, the security property we want from CORB/ORB is this: For any
"no-cors" request we want positive evidence that the response received
is of the intended data type.

Note:
* CORB/ORB has nothing to add for non-"no-cors" requests.
* We require this evidence before handing the resource data off to the renderer.
* For "positive evidence" we accept a conservative approximation.
  It's not okay to block a valid resource; but it might well be okay to
  occasionally let an inappropriate resource pass.
* A "correct" MIME type is good enough evidence.
* A "wrong" MIME type is good enough counter evidence.
* For historic reasons, browsers accept a number of resources with
  inappropriate MIME types. For these historically accepted MIME types,
  we require "content sniffing" to provide us with the desired evidence.

## A Note on Deprecations

Both CORB and ORB are [deprecations](https://developer.chrome.com/blog/deps-rems-101/)
at heart. That is: Formerly allowed behaviour would be newly disallowed and
blocked. This invariably causes issues for some well-meaning websites that,
often inadvertently, rely on the behaviour to be deprecated.
Any deprecation requires great care when deploying in order to minimize
unintended side-effects on the web ecosystem.

# The Solution(s)

## Cross-Origin Read Blocking (CORB)

[Cross-Origin Read Blocking](https://www.chromium.org/Home/chromium-security/corb-for-developers/)
identifies a number of resource types that should be protected, namely
HTML, XML (except SVG), and JSON, and blocks them from being loaded in
"no-cors" responses. None of the intended usages for these resource types
issue "no-cors" requests. In addition to MIME type checks, it also employs
"sniffers" for these formats.

The full details are more complicated. Here, we'll skip over details of
sniffing, error handling, and partial content responses (HTTP 206 responses).
Additional details can be found
[here](https://chromium.googlesource.com/chromium/src/+/main/services/network/cross_origin_read_blocking_explainer.md) and [here](https://www.chromium.org/Home/chromium-security/corb-for-developers/).

Note that this is a partial mismatch for our security requirements: Instead
of requiring positive evidence for the intended format, we instead picked a
handful of known-bad cases. Essentially, we look for negative evidence
for a request type mismatch, and ignore all the cases for which we don't have
such evidence.

## Opaque Resource Blocking (ORB)

[ORB](https://github.com/annevk/orb) is an alternative proposal to solve the
same problem. In Chromium we intend to replace CORB with ORB, so that in
the context of Chromium ORB could be considered as a "version 2" of CORB.

The fundamental difference between CORB and ORB is that CORB picked
specific type mismatches to disallow, while ORB enumerates the data formats
that we expect to occur in "no-cors" requests and blocks the rest.
This makes ORB a better fit for our security requirements. It also makes ORB
a much bigger risk for web compatibility.

## "ORB v0.1"

Since CORB/ORB are deprecations, great care must be taken to not
break legitimate web sites. Since no implementation of ORB exists
(as of 2022-05), we have no existing web compatibiltiy data and must thus
be careful in deploying ORB.

As a first step we are implementing a subset, dubbed "ORB v0.1". This differs
from ORB as proposed:

- It is more permissive with several resource types: `audio/*`, `video/*`,
  and some XML MIME types.
- It does not implement the JavaScript parsing steps. Instead it
  re-uses several sniffers from CORB:
  [HTML](https://chromium.googlesource.com/chromium/src/+/main/services/network/cross_origin_read_blocking_explainer.md#protecting-html),
  [XML](https://chromium.googlesource.com/chromium/src/+/main/services/network/cross_origin_read_blocking_explainer.md#protecting-xml), and
  [JSON and "XSSI-defeating prefixes"](https://chromium.googlesource.com/chromium/src/+/main/services/network/cross_origin_read_blocking_explainer.md#protecting-json).
- It will accept any response for which these heuristics do not deliver a
  verdict.
- CORB error handling is re-used: If a response is blocked, an empty response
  will be injected in its stead. (ORB proposes an error response.)

One unfortunate effect of postponing JSON and JavaScript sniffing is that
"ORB v0.1" does not yet achieve our goal of blocking any resource for which
we do not have positive evidence.

## ORB post v0.1

These plans are not settled. We will iterate towards a more complete ORB
implementation. Note that some ORB details are also not finalized yet.

# Appendix: Implementation and Spec Status

## CORB

* Implemented & shipped: Chrome M67
* Spec: Formerly https://fetch.spec.whatwg.org/#corb (removed [here](https://github.com/whatwg/fetch/commit/78f9bdd73e8c6893d629c2ce4a3bde7eb01cac59))

## "ORB v0.1"

* Spec: n/a. Follows the [ORB](https://github.com/annevk/orb) proposal, but
  with several differences, noted below.
* Implemented & shipped: [Intent here](https://groups.google.com/u/1/a/chromium.org/g/blink-dev/c/ScjhKz3Z6U4/m/kW5RjWamAQAJ)

## ORB

* Draft Spec: https://github.com/annevk/orb
* Implementation: Under discussion.

# Appendix: Differences between "ORB v0.1" and ORB

The main difference is that "ORB v0.1" is more permissive, to reduce web
compatibility risks. A more detailed write-up may be found
[here](https://docs.google.com/document/d/1qUbE2ySi6av3arUEw5DNdFJIKKBbWGRGsXz_ew3S7HQ/edit#heading=h.mptmm5bpjtdn).

Below are the tabulated differences between "ORB v0.1" and the ORB proposal.
Decisions are based on four factors:

* The response's MIME type,
* the response's "nosniff" header,
* several "sniffers" that heuristically examine the first 1KiB of data,
* and parsers for the full resource (ORB only).

| | "ORB v0.1" | ORB | Comment |
| --- | --- | --- | --- |
| MIME type: JavaScript | n/a (allow, unless it "sniffs" wrong. This follows from the rules below.) | **allow** (without sniffing) | Known-good "no-cors" MIME types.
| MIME type: HTML, JSON, XML, text/plain | **block** (if nosniff) | **block** (if nosniff) | MIME types that have historically been accepted in "no-cors" requests. We hope developers set the "nosniff" header.
| MIME type: zip + gzip, various MS office types; protobuf, text/csv | **block** | **block** | "Never sniff" MIME types. Not allowed in any "no-cors" requests.
| MIME type: audio/* or video/* | **allow** | **block** (unless it "sniffs" okay. This follows from the rules below. I'd expect most resources to "sniff" okay, though, so in practice these would likely be mostly allowed.) | "ORB v0.1" relaxes audio + video handling, and just lets all audio + video MIME types pass.
| MIME type: n/a (invalid/missing MIME type) | n/a (rules below apply. Would probably mostly allow.) | **allow** | |
| sniffs as audio/*, video/*, image/* | **allow** | **allow** | |
| JSON / JS handling | **block** if first 1KiB bytes sniff as <ul><li>HTML (but not MIME type: CSS),</li><li>XML (but not MIME type: SVG),</li><li>JS parser breaker,</li><li>or JSON.</li></ul> | **block** if "nosniff", **allow** if parses (!!) as JavaScript, **block** otherwise. (E.g. JSON or HTML or PDF won’t parse as JS.) | "ORB v0.1" makes a very deliberate decision to not parse a full response.
| default | **allow** | **block** | Because "ORB v0.1" can only "sniff" certain JS anti-patterns, it has to make the unfortunate decision to allow unknown content. We'd very much like to fix this, without the cost of a full parse.

The table omits:

* Blocked response handling: "ORB v0.1" injects empty responses instead of
  returning an error.
* Handling of range requests / partial content responses (HTTP 206 responses).