annevk / orb

Opaque Response Blocking (CORB++)
Creative Commons Zero v1.0 Universal
34 stars 4 forks source link

Opaque Response Blocking (ORB, aka CORB++)

Status

This repository is being upstreamed to the Fetch Standard through PR #1442. As indicated there you can preview a version of the Fetch Standard with the new text integrated.

The PR is primarily blocked on resolving the mvp issues. Help appreciated!

The PR is in a more advanced state than the text below and should be the starting point for implementers and reviewers.

Objective

To block as many opaque responses as possible while remaining web compatible.

High-level idea

CSS, JavaScript, images, and media (audio and video) can be requested across origins without CORS. Except for CSS there is no MIME type enforcement. Ideally we still block as many responses as possible that are not one of these types to avoid leaking their contents through side channels.

Processing model

New MIME type sets

An opaque-safelisted MIME type is a JavaScript MIME type or a MIME type whose essence is "text/css" or "image/svg+xml".

An opaque-blocklisted MIME type is an HTML MIME type, JSON MIME type, or XML MIME type.

An opaque-blocklisted-never-sniffed MIME type is a MIME type whose essence is one of

Changes to requests and media elements

A request has an associated no-cors media request state ("N/A", "initial", or "subsequent"). It is "N/A" unless explicitly stated otherwise.

We adjust the way media element fetching is done to more clearly separate between the initial and any subsequent range fetches:

(These changes are not needed when CORS is used, but it might make sense to align these somewhat, to the extent they are not already.)

ORB's algorithm

To determine whether to allow response response to a request request, run these steps:

  1. Let mimeType be the result of extracting a MIME type from response's header list.
  2. Let nosniff be the result of determining nosniff given response's header list.
  3. If mimeType is not failure, then:
    1. If mimeType is an opaque-safelisted MIME type, then return true.
    2. If mimeType is an opaque-blocklisted-never-sniffed MIME type, then return false.
    3. If response's status is 206 and mimeType is an opaque-blocklisted MIME type, then return false.
    4. If nosniff is true and mimeType is an opaque-blocklisted MIME type or its essence is "text/plain", then return false.
  4. If request's no-cors media request state is "subsequent", then return true.
  5. If response's status is 206 and validate a partial response given 0 and response returns invalid, then return false.
  6. Wait for 1024 bytes of response or end-of-file, whichever comes first and let bytes be those bytes.
  7. If the audio or video type pattern matching algorithm given bytes does not return undefined, then:
    1. If requests's no-cors media request state is not "initial", then return false.
    2. If response's status is not 200 or 206, then return false.
    3. Return true.
  8. If requests's no-cors media request state is not "N/A", then return false.
  9. If the image type pattern matching algorithm given bytes does not return undefined, then return true.
  10. If nosniff is true, then return false.
  11. If response's status is not an ok status, then return false.
  12. If mimeType is failure, then return true.
  13. If mimeType's essence starts with "audio/", "image/", or "video/", then return false.
  14. Wait for end-of-file of response's body. Note: as discussed in GitHub's annevk/orb #22 partially parsing JavaScript is unfortunately infeasible. This might end up leaking the size of responses that hit this step.
  15. If response's body parses as JavaScript and does not parse as JSON, then return true.
  16. Return false.

Note: responses for which the above algorithm returns true and contain secrets are strongly encouraged to be protected using Cross-Origin-Resource-Policy.

Implementation considerations

Setting request's no-cors media request state to "subsequent" ideally happens in a process that is not easily compromised, because such a spoofed value can be used to bypass ORB. In particular, "subsequent" is only to be allowed and used if a trustworthy process can verify that the media element (or its node document, or its node document's origin) has previously received a response with the same URL that has sniffed as audio or video.

Findings

Acknowledgments

Many thanks to Jake Archibald, Lukasz Anforowicz, Nathan Froyd, and those involved in Chromium's CORB project.