1# Cross-Origin Read Blocking (CORB) 2 3This document outlines Cross-Origin Read Blocking (CORB), an algorithm by which 4dubious cross-origin resource loads may be identified and blocked by web 5browsers before they reach the web page. 6CORB reduces the risk of leaking sensitive data by keeping it further from 7cross-origin web pages. In most browsers, it keeps such data out of untrusted 8script execution contexts. In browsers with 9[Site Isolation](https://www.chromium.org/Home/chromium-security/site-isolation), 10it can keep such data out of untrusted renderer processes entirely, helping even 11against side channel attacks. 12 13[TOC] 14 15## The problem 16 17The same-origin policy generally prevents one origin from reading arbitrary 18network resources from another origin. In practice, enforcing this policy is not 19as simple as blocking all cross-origin loads: exceptions must be established for 20web features, like `<img>` or `<script>` which can target cross-origin 21resources for historical reasons, and for the CORS mechanism which allows some 22resources to be selectively read across origins. 23 24Certain types of content, however, can be shown to be incompatible with all of 25the historically-allowed permissive contexts. JSON is one such type: a JSON 26response will result in a decode error when targeted by the `<img>` tag, either 27a no-op or syntax error when targeted by the `<script>` tag, and so on. The 28only case where a web page can load JSON with observable consequences, is via 29`fetch()` or `XMLHttpRequest`; and in those cases, cross-origin reads are 30moderated by CORS. 31 32By detecting and blocking loads of CORB-protected resources early -- that is, 33before the response makes it to the image decoder or JavaScript parser stage -- 34CORB defends against side channel vulnerabilities that may be present in the 35stages which are skipped. 36 37## What attacks does CORB mitigate? 38 39CORB mitigates the following attack vectors: 40 41* Cross-Site Script Inclusion (XSSI) 42 * XSSI is the technique of pointing the `<script>` tag at a target resource 43 which is not JavaScript, and observing some side effects when the resulting 44 resource is interpreted as JavaScript. An early example of this attack was 45 discovered in 2006: by overwriting the JavaScript Array constructor, the 46 contents of JSON lists could be intercepted as simply as: 47 `<script src="https://example.com/secret.json">`. 48 While the array constructor attack vector is fixed in current 49 browsers, numerous similar exploits have been found and fixed in the 50 subsequent decade. For example, see the 51 [slides here](https://www.owasp.org/images/6/6a/OWASPLondon20161124_JSON_Hijacking_Gareth_Heyes.pdf). 52 * CORB prevents this class of attacks, because a CORB-protected resource will 53 be blocked from ever being delivered to a cross-site `<script>` element. 54 * CORB is particularly valuable in absence of other XSSI defenses like 55 [XSRF tokens](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#synchronizer-token-pattern) 56 and/or 57 [JSON security prefixes](https://docs.angularjs.org/api/ng/service/$http#json-vulnerability-protection). 58 Additionally, the presence of XSSI defenses like 59 [JSON security prefixes](https://docs.angularjs.org/api/ng/service/$http#json-vulnerability-protection) 60 can also be used as a signal to the CORB algorithm that a resource should be 61 CORB-protected. 62 63* Speculative Side Channel Attack (e.g. Spectre). 64 * For example, an attacker may use an 65 `<img src="https://example.com/secret.json">` 66 element to pull a cross-site secret 67 into the process where the attacker's JavaScript runs, and then use a 68 speculative side channel attack (e.g. [Spectre](https://spectreattack.com)) 69 to read the secret. 70 * CORB can prevent this class of attacks when used in tandem with 71 [Site Isolation](https://www.chromium.org/Home/chromium-security/site-isolation), 72 by preventing the JSON resource from being present in the 73 memory of a process hosting a cross-site page. 74 75## How does CORB "block" a response? 76 77When CORB decides that a response needs to be CORB-protected, the response is 78modified as follows: 79* The response body is replaced with an empty body. 80* The response headers are removed. 81 82> [lukasza@chromium.org] Chromium currently retains Access-Control-\* headers 83> (this helps generate better error messages for CORS). 84 85To be effective against speculative side-channel attacks, CORB blocking must 86take place before the response reaches the process hosting the cross-origin 87initiator of the request. In other words, CORB blocking should prevent 88CORB-protected response data from ever being present in the memory of the 89process hosting a cross-origin website (even temporarily or for a short term). 90This is different from the concept of 91[filtered responses](https://fetch.spec.whatwg.org/#concept-filtered-response) 92(e.g. [CORS filtered response](https://fetch.spec.whatwg.org/#concept-filtered-response-cors) or 93[opaque filtered response](https://fetch.spec.whatwg.org/#concept-filtered-response-opaque)) 94which just provide a limited view into full data that remains stored in an 95[internal response](https://fetch.spec.whatwg.org/#concept-internal-response) 96and may be implemented inside the renderer process. 97 98A CORB demo page 99[is available here](https://anforowicz.github.io/xsdb-demo/index.html). 100 101## What kinds of requests are CORB-eligible? 102 103The following kinds of requests are CORB-exempt: 104 105* [navigation requests](https://fetch.spec.whatwg.org/#navigation-request) 106 or requests where the 107 [request destination](https://fetch.spec.whatwg.org/#concept-request-destination) 108 is "object" or "embed". 109 Cross-origin `<iframe>`s, `<object>`s, and `<embed>`s create a separate 110 security context and thus pose less risk for leaking the data. In most 111 browsers, this separate context means that a malicious page would have more 112 trouble inferring the contents than from loading them into its own execution 113 context and observing side effects (e.g., XSSI, style tags, etc). In browsers 114 with Site Isolation, this security context uses a separate process, keeping 115 the data out of the malicious page's address space entirely. 116 117> [lukasza@chromium.org] TODO: Figure out how 118> [Edge's VM-based isolation](https://cloudblogs.microsoft.com/microsoftsecure/2017/10/23/making-microsoft-edge-the-most-secure-browser-with-windows-defender-application-guard/) 119> works (e.g. if some origins are off-limits in particular renderers, then this 120> would greatly increase utility of CORB in Edge). 121 122* Download requests (e.g. requests where the 123 [initiator](https://fetch.spec.whatwg.org/#concept-request-initiator) 124 is "download"). In this case the data from the response is saved to disk 125 (instead of being shared to a cross-origin context) and therefore wouldn't 126 benefit from CORB protection. 127 128> [lukasza@chromium.org] AFAIK, in Chrome a response to a download request never 129> passes through memory of a renderer process. Not sure if this is true in 130> other browsers. 131 132All other kinds of requests may be CORB-eligible. This includes: 133* [XHR](https://xhr.spec.whatwg.org/) 134 and [fetch()](https://fetch.spec.whatwg.org/#dom-global-fetch) 135* `ping`, `navigator.sendBeacon()` 136* `<link rel="prefetch" ...>` 137* Requests with the following 138 [request destination](https://fetch.spec.whatwg.org/#concept-request-destination): 139 - "image" requests like `<img>` tag, `/favicon.ico`, SVG's `<image>`, 140 CSS' `background-image`, etc. 141 - [script-like destinations](https://fetch.spec.whatwg.org/#request-destination-script-like) 142 like `<script>`, `importScripts()`, `navigator.serviceWorker.register()`, 143 `audioWorklet.addModule()`, etc. 144 - "audio", "video" or "track" 145 - "font" 146 - "style" 147 - "report" requests like CSP reports, NEL reports, etc. 148 149The essential idea of CORB is to consider whether a particular resource might be 150unsuitable for use in *every* context listed above. If every possible usage 151would result in either a CORS error, a syntax/decoding error, or no observable 152consequence, CORB ought to be able to block the cross-origin load without 153changing the observable consequences of the load. Prior to CORB, details are 154already suppressed from cross-origin errors, to prevent information leaks. Thus, 155the observable consequences of such errors are already limited, and feasible to 156preserve while blocking. 157 158## What types of content are protected by CORB? 159 160As discussed below, the following types of content are CORB-protected: 161 * JSON 162 * HTML 163 * XML 164 165These are each discussed in the following sections. 166 167### Protecting JSON 168 169JSON is a widely used data format on the web; support for JSON is built into the 170web platform. JSON responses are very likely to contain user data worth 171protecting. Additionally, unlike HTML or image formats, there are no legacy HTML 172mechanisms (that is, predating CORS) which allow cross-origin embedding of JSON 173resources. 174 175Because the JSON syntax is derived from and overlaps with JavaScript, care must 176be taken to handle the possibility of JavaScript/JSON polyglots. 177CORB handles the following cases for JSON: 178 * Non-empty JSON object literal: A non-empty JSON object 179 (such as `{"key": "value"}`). This is precisely the subset of JSON syntax 180 which is invalid JavaScript syntax -- the colon after the first string 181 literal will generate a syntax error. CORB can protect these cases, even if 182 labeled with a different Content-Type, by sniffing the response body. 183 * Other JSON literals: The remaining subset of the JSON syntax (for example, 184 `null` or `[1, 2, "3"]`) also happens to be valid JavaScript syntax. In 185 particular, when evaluated as script, they are value expressions that should 186 have no side effects. Thus, if they can be detected, they can be CORB- 187 protected. Detection here is possible, but requires implementing a validator 188 that understands the full JSON syntax: 189 * If the response is not labeled with a JSON Content Type, CORB might detect 190 these cases by buffering and validating the entire response body as 191 JSON; the entire response must be considered because of the potential for 192 a valid, side-effect-having JavaScript program like `[1, 2, 193 "3"].map(...)`. 194 * If the response is indeed labeled with a JSON Content Type, CORB may 195 decide to sniff the response to confirm it is valid JSON, only up to a 196 certain number of bytes. This would avoid buffering and parsing 197 in an unbounded amount of memory. 198 * JSON served with 199 [an XSSI-defeating prefix](https://docs.angularjs.org/api/ng/service/$http#json-vulnerability-protection): 200 As a mitigation for past browser 201 vulnerabilities, many actual websites and frameworks employ a convention of 202 prefixing their fetchable resources with a string designed to force a 203 JavaScript error. 204 These prefixes have not been standardized prior to CORB, but a few approaches 205 seem prevalent: 206 207 * The character sequence `)]}'` is built into 208 [the angular.js framework](https://docs.angularjs.org/api/ng/service/$http), 209 [the Java Spring framework](https://goo.gl/xP7FWn), 210 and is observed in wide use on the google.com domain. 211 * The character sequence `{} &&` was 212 [historically built into the Java Spring framework](https://goo.gl/JYPFAv). 213 * Infinite loops, such as `for(;;);`, are observed in wide use on the 214 facebook.com domain. 215 216 The presence of these recognized XSSI defenses is a 217 strong signal to the CORB algorithm that a resource should be CORB-protected. 218 As such, these prefixes should trigger CORB protection in almost every case, 219 no matter what follows them. This is argued to be safe because: 220 * [A JSON security prefix](https://docs.angularjs.org/api/ng/service/$http#json-vulnerability-protection) 221 would cause a syntax error (or a hang) if present in a document served 222 with a JavaScript MIME type such as `text/javascript`. 223 * [JSON security prefixes](https://docs.angularjs.org/api/ng/service/$http#json-vulnerability-protection) 224 are not known to collide with binary 225 resources like images, videos or fonts (which typically require 226 the first few bytes to be hardcoded to a specific sequence - for example 227 `FF D8 FF` for image/jpeg). 228 * Collisions with `text/css` stylesheets are theoretically possible, because 229 it is possible to construct a file that begins with 230 [a JSON security prefix](https://docs.angularjs.org/api/ng/service/$http#json-vulnerability-protection), 231 but at the same parses fine as a stylesheet. 232 `text/css` is therefore established as an exception, even though the 233 practical likelihood of such a scenario seems low. 234 See below for an example of such a stylesheet: 235```css 236)]}' 237{} 238h1 { color: red; } 239``` 240 241JSON is also used by some web features. One example is `<link 242rel="manifest">`, whose `href` attribute specifies a JSON manifest file. 243Fortunately, this mechanism requires CORS when the manifest is specified cross- 244origin, so its CORB treatment works identically to the rules applied to fetch(). 245 246> [nick@chromium.org] TODO: Is there a spec link for JSON being side-effect 247> free when interpreted as script? 248 249### Protecting HTML 250 251HTML can be embedded cross-origin via `<iframe>` (as noted above), 252but otherwise HTML documents can 253only be loaded by fetch() and XHR, both of which require CORS. HTML sniffing is 254already well-understood, so (unlike JSON) it is relatively easy to identify HTML 255resources with high confidence. 256 257One ambiguous polyglot case has been 258identified that CORB needs to handle conservatively: HTML-style comments, which 259are [part of the JavaScript syntax](https://www.ecma-international.org/ecma-262/8.0/index.html#sec-html-like-comments). 260* CORB skips over HTML comment blocks when sniffing to 261 confirm a HTML content type. This means that (unlike in 262 [normal HTML sniffing](https://mimesniff.spec.whatwg.org/#identifying-a-resource-with-an-unknown-mime-type)) 263 presence of "`<!--`" string doesn't immediately confirm that the sniffed resource is a 264 HTML document - the HTML comment still has to be followed by a valid HTML tag. 265* Additionally, after the end of a HTML comment, the CORB sniffer will skip all 266 characters until a line terminating character. This helps accomodate the 267 [`SingleLineHTMLCloseComment`](https://www.ecma-international.org/ecma-262/8.0/index.html#prod-annexB-SingleLineHTMLCloseComment) 268 rule which can consume 269 [`SingleLineCommentChars`](https://www.ecma-international.org/ecma-262/8.0/index.html#prod-SingleLineCommentChars) 270 _after_ the "`-->`" characters. 271 272Examples of html/javascript polyglots which have been observed 273in use on real websites: 274```js 275<!--/*--><html><body><script type="text/javascript"><!--//*/ 276var x = "This is both valid html and valid javascript"; 277//--></script></body></html> 278``` 279 280```js 281<!-- comment --> <script type='text/javascript'> 282//<![CDATA[ 283var x = "This is both valid html and valid javascript"; 284//]]>--></script> 285``` 286 287 288### Protecting XML 289 290XML, like JSON, is a widely used data exchange format, and like HTML, is a 291document format that's built into the web platform (notably via XmlHttpRequest). 292 293Confirming an XML content-type via sniffing is more straightforward than JSON or 294HTML: XML is signified by the pattern `<?xml`, possibly preceded by whitespace. 295 296The only identified XML case that requires special treatment by CORB is 297`image/svg+xml`, which is an image type. All other XML mime types are treated as 298CORB-protected. 299 300## Determining whether a response is CORB-protected 301 302CORB decides whether a response needs protection (i.e. if a response is a JSON, 303HTML or XML resource) based on the following: 304 305* If the response contains `X-Content-Type-Options: nosniff` response header, 306 then the response will be CORB-protected 307 if its `Content-Type` header is one of the following: 308 * [HTML MIME type](https://mimesniff.spec.whatwg.org/#html-mime-type) 309 * [XML MIME type](https://mimesniff.spec.whatwg.org/#xml-mime-type) 310 (except `image/svg+xml` which is CORB-exempt as described above) 311 * [JSON MIME type](https://mimesniff.spec.whatwg.org/#json-mime-type) 312 * `text/plain` 313 314* If the response is a 206 response, 315 then the response will be CORB-protected 316 if its `Content-Type` header is one of the following: 317 * [HTML MIME type](https://mimesniff.spec.whatwg.org/#html-mime-type) 318 * [XML MIME type](https://mimesniff.spec.whatwg.org/#xml-mime-type) 319 (except `image/svg+xml` which is CORB-exempt as described above) 320 * [JSON MIME type](https://mimesniff.spec.whatwg.org/#json-mime-type) 321 322* Otherwise, CORB attempts to sniff the response body: 323 * [HTML MIME type](https://mimesniff.spec.whatwg.org/#html-mime-type) 324 that sniffs as HTML is CORB-protected 325 * [XML MIME type](https://mimesniff.spec.whatwg.org/#xml-mime-type) 326 (except `image/svg+xml`) that sniffs as XML is CORB-protected 327 * [JSON MIME type](https://mimesniff.spec.whatwg.org/#json-mime-type) 328 that sniffs as JSON is CORB-protected 329 * `text/plain` that sniffs as JSON, HTML or XML is CORB-protected 330 * Any response (except `text/css`) that begins with 331 [a JSON security prefix](https://docs.angularjs.org/api/ng/service/$http#json-vulnerability-protection) 332 is CORB-protected 333 334The sniffing is necessary to avoid blocking existing web pages that depend on 335mislabeled cross-origin responses (e.g. on images served as `text/html`). 336Without sniffing CORB would block around 16 times as many 337responses. 338* CORB will only sniff to *confirm* the classification based on the `Content-Type` 339 header (i.e. if the `Content-Type` header is `text/json` then CORB will sniff 340 for JSON and will not sniff for HTML or XML). 341* If some syntax elements are shared between CORB-protected and 342 non-CORB-protected MIME types, then these elements have to be ignored by CORB 343 sniffing. For example, when sniffing for (CORB-protected) HTML, CORB ignores 344 and skips HTML comments, because 345 [they can also be present](http://www.ecma-international.org/ecma-262/6.0/#sec-html-like-comments) 346 in (non-CORB-protected) JavaScript. This is different from the 347 [HTML sniffing rules](https://mimesniff.spec.whatwg.org/#rules-for-identifying-an-unknown-mime-type), 348 used in other contexts. 349* Sniffing is a best-effort heuristic and for best security results, we 350 recommend that web developers 1) mark responses with the correct `Content-Type` 351 header and 2) opt out of sniffing by using the 352 `X-Content-Type-Options: nosniff` header. 353 354> [nick@chromium.org] This section needs a strong justification for why 355> text/plain gets this special interpretation. Ideally data showing that 356> text/plain is commonly used to serve HTML, JSON, or XML. Treatment of 357> text/plain in our current implementation may actually be an artifact of 358> an earlier prototype, which ran after standard mime sniffing, and may have 359> seen 'text/plain' MIME types applied as a default MIME type when the response 360> omitted a Content-Type header. 361 362Note that the above means that the following responses are not CORB-protected: 363* Responses labeled as `multipart/*`. 364 This avoids having to parse the content types of the nested parts. 365 We recommend not supporting multipart range requests for sensitive documents. 366* Responses without a `Content-Type` header. 367* Responses with a JavaScript MIME type such as `text/javascript`. This 368 includes JSONP ("JSON with padding") which unlike JSON is meant to be read 369 and executed in a cross-origin context. 370 371 372## CORB and web compatibility 373 374### Observable CORB impact on images 375 376CORB should have no observable impact on `<img>` tags unless the image resource 377is both 1) mislabeled with an incorrect, non-image, CORB-protected Content-Type 378and 2) served with the `X-Content-Type-Options: nosniff` response header. 379 380Examples: 381 382* **Correctly-labeled HTML document** 383 * Resource used in an `<img>` tag: 384 * Body: an HTML document 385 * `Content-Type: text/html` 386 * No `X-Content-Type-Options` header 387 * Expected behavior: **no observable difference**. 388 The rendered image should be the same broken image when 1) attempting 389 to render an html document as an image (without CORB) and 2) attempting to 390 render an empty response as an image (when CORB blocks the response). 391 * WPT test: `fetch/corb/img-html-correctly-labeled.sub.html` 392 393* **Mislabeled image (with sniffing)** 394 * Resource used in an `<img>` tag: 395 * Body: an image 396 * `Content-Type: text/html` 397 * No `X-Content-Type-Options` header 398 * Expected behavior: **no difference**. 399 CORB will sniff that the response body is *not* actually a CORB-protected 400 type and therefore will allow the response. 401 * WPT test: `fetch/corb/img-png-mislabeled-as-html.sub.html` 402 403* **Mislabeled image (nosniff)** 404 * Resource used in an `<img>` tag: 405 * Body: an image 406 * `Content-Type: text/html` 407 * `X-Content-Type-Options: nosniff` 408 * Expected behavior: **observable difference**. 409 Because of the `nosniff` header, CORB will have to rely on the 410 `Content-Type` header. Because this response is mislabeled (the body is an 411 image, but the `Content-Type` header says that it is a html document), CORB 412 will incorrectly classify the response as requiring CORB-protection. 413 * WPT test: `fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html` 414 415In addition to the HTML `<img>` tag, the examples above should apply to other 416web features that consume images - including, but not limited to: 417* `/favicon.ico` 418* SVG's `<image>`, 419* `<link rel="preload" as="image" ...>` (see WPT test: 420 `fetch/corb/preload-image-png-mislabeled-as-html-nosniff.tentative.sub.html`) 421* `background-image` in stylesheets 422* painting images onto (potentially tainted) HTML's `<canvas>` 423 424> [lukasza@chromium.org] Earlier attempts to block nosniff images with 425> incompatible MIME types 426> [failed](https://github.com/whatwg/fetch/issues/395). 427> We think that CORB will have more luck, because 428> it will only block a subset of CORB-protected MIME types 429> (e.g. it won't block `application/octet-stream` as quoted in a 430> [Firefox bug](https://bugzilla.mozilla.org/show_bug.cgi?id=1302539)) 431 432 433### Observable CORB impact on multimedia 434 435Audio and video resources should see similar impact as images, though 206 436responses are more likely to occur for media. 437 438### Observable CORB impact on scripts 439 440CORB should have no observable impact on `<script>` tags except for cases where 441a CORB-protected, non-JavaScript resource labeled with its correct MIME type is 442loaded as a script - in these cases the resource will usually result in a syntax 443error, but CORB-protected response's empty body will result in no error. 444 445Examples: 446 447* **Correctly-labeled HTML document** 448 * Resource used in a `<script>` tag: 449 * Body: an HTML document 450 * `Content-Type: text/html` 451 * No `X-Content-Type-Options` header 452 * Expected behavior: **observable difference** via 453 [GlobalEventHandlers.onerror](https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror). 454 Most CORB-protected resources would result in a syntax error when parsed as 455 JavaScript. The syntax error goes away after CORB blocks a response, 456 because the empty body of the blocked response parses fine as JavaScript. 457 * WPT test: `fetch/corb/script-html-correctly-labeled.tentative.sub.html` 458 459> [lukasza@chromium.org] In theory, using a non-empty response in CORB-blocked 460> responses might reintroduce the lost syntax error. We didn't go down that 461> path, because 462> 1) using a non-empty response would be inconsistent with other parts of the 463> Fetch spec (like 464> [opaque filtered response](https://fetch.spec.whatwg.org/#concept-filtered-response-opaque)). 465> 2) retaining the presence of the syntax error might require changing the 466> contents of a CORB-blocked response body depending on whether the original 467> response body would have caused a syntax error or not. This would add 468> extra complexity that seems undesirable both for CORB implementors and for 469> web developers. 470 471* **Mislabeled script (with sniffing)** 472 * Resource used in a `<script>` tag: 473 * Body: a proper JavaScript script 474 * `Content-Type: text/html` 475 * No `X-Content-Type-Options` header 476 * Expected behavior: **no difference**. 477 CORB will sniff that the response body is *not* actually a CORB-protected 478 type and therefore will allow the response. Note that CORB sniffing is 479 resilient to the fact that some syntax elements are shared across HTML 480 and JavaScript (e.g. 481 [comments](http://www.ecma-international.org/ecma-262/6.0/#sec-html-like-comments)). 482 * WPT test: `fetch/corb/script-js-mislabeled-as-html.sub.html` 483 484* **Mislabeled script (nosniff)** 485 * Resource used in a `<script>` tag: 486 * Body: a proper JavaScript script 487 * `Content-Type: text/html` 488 * `X-Content-Type-Options: nosniff` 489 * Expected behavior: **no observable difference**. 490 Both with and without CORB, the script will not execute, because the 491 `nosniff` response header response will cause the response to be blocked 492 when its MIME type (`text/html` in the example) is not a 493 [JavaScript MIME type](https://html.spec.whatwg.org/multipage/scripting.html#javaScript-mime-type) 494 (this behavior is required by the 495 [Fetch spec](https://fetch.spec.whatwg.org/#should-response-to-request-be-blocked-due-to-nosniff?)). 496 * WPT test: `fetch/corb/script-js-mislabeled-as-html-nosniff.sub.html` 497 498In addition to the HTML `<script>` tag, the examples above should apply to other 499web features that consume JavaScript including 500[script-like destinations](https://fetch.spec.whatwg.org/#request-destination-script-like) 501like `importScripts()`, `navigator.serviceWorker.register()`, 502`audioWorklet.addModule()`, etc. 503 504 505### Observable CORB impact on stylesheets 506 507CORB should have no observable impact on stylesheets. 508 509Examples: 510 511* **Anything not labeled as text/css** 512 * Examples of resources used in a `<link rel="stylesheet" href="...">` tag: 513 * Body: an HTML document OR a simple, valid stylesheet OR a polyglot 514 HTML/CSS stylesheet 515 * `Content-Type: text/html` 516 * No `X-Content-Type-Options` header 517 * Expected behavior: **no observable difference**. 518 Even without CORB, such stylesheet examples will be rejected, because 519 due to the 520 [relaxed syntax rules](https://scarybeastsecurity.blogspot.dk/2009/12/generic-cross-browser-cross-domain.html) 521 of CSS, cross-origin CSS requires a correct Content-Type header 522 (restrictions vary by browser: 523 [IE](http://msdn.microsoft.com/en-us/library/ie/gg622939%28v=vs.85%29.aspx), 524 [Firefox](http://www.mozilla.org/security/announce/2010/mfsa2010-46.html), 525 [Chrome](https://bugs.chromium.org/p/chromium/issues/detail?id=9877), 526 [Safari](http://support.apple.com/kb/HT4070) 527 (scroll down to CVE-2010-0051) and 528 [Opera](http://www.opera.com/support/kb/view/943/)). 529 This behavior is covered by 530 [the HTML spec](https://html.spec.whatwg.org/#link-type-stylesheet) 531 which 1) asks to only assume `text/css` Content-Type 532 if the document embedding the stylesheet has been set to quirks mode and has 533 the same origin and 2) only asks to run the steps for creating a CSS style 534 sheet if Content-Type of the obtained resource is `text/css`. 535 536 * WPT tests: 537 `fetch/corb/style-css-mislabeled-as-html.sub.html`, 538 `fetch/corb/style-html-correctly-labeled.sub.html` 539 540* **Anything not labeled as text/css (nosniff)** 541 * Resource used in a `<link rel="stylesheet" href="...">` tag: 542 * Body: a simple stylesheet 543 * `Content-Type: text/html` 544 * `X-Content-Type-Options: nosniff` 545 * Expected behavior: **no observable difference**. 546 Both with and without CORB, the stylesheet will not load, because the 547 `nosniff` response header response will cause the response to be blocked 548 when its MIME type (`text/html` in the example) is not `text/css` 549 (this behavior is required by the 550 [Fetch spec](https://fetch.spec.whatwg.org/#should-response-to-request-be-blocked-due-to-nosniff?)). 551 * WPT test: `fetch/corb/style-css-mislabeled-as-html-nosniff.sub.html` 552 553* **Correctly-labeled stylesheet with a JSON security prefix** 554 * Resource used in a `<link rel="stylesheet" href="...">` tag: 555 * Body: a stylesheet that begins with 556 [a JSON security prefix](https://docs.angularjs.org/api/ng/service/$http#json-vulnerability-protection) 557 * `Content-Type: text/css` 558 * No `X-Content-Type-Options` header 559 * Expected behavior: **no difference**, 560 because CORB sniffing for 561 [JSON security prefixes](https://docs.angularjs.org/api/ng/service/$http#json-vulnerability-protection) 562 is not performed for responses labeled as `Content-Type: text/css`. 563 * WPT test: `fetch/corb/style-css-with-json-parser-breaker.sub.html` 564 565 566### Observable CORB impact on other web platform features 567 568CORB has no impact on the following scenarios: 569 570* **[XHR](https://xhr.spec.whatwg.org/) and 571 [fetch()](https://fetch.spec.whatwg.org/#dom-global-fetch)** 572 * CORB has no observable effect, because [XHR](https://xhr.spec.whatwg.org/) 573 and [fetch()](https://fetch.spec.whatwg.org/#dom-global-fetch) already apply 574 same-origin policy to the responses (e.g. CORB should only block responses 575 that would result in cross-origin XHR errors because of lack of CORS). 576 577* **[Prefetch](https://html.spec.whatwg.org/#link-type-prefetch)** 578 * CORB blocks response body from reaching a cross-origin renderer, but 579 CORB doesn't prevent the response body from being cached by the browser 580 process (and subsequently delivered into another, same-origin renderer 581 process). 582 583* **Tracking and reporting** 584 * Various techniques try to check that a user has accessed some content 585 by triggering a web request to a HTTP server that logs the user visit. 586 The web request is frequently triggered by an invisible `img` element 587 to a HTTP URI that usually replies either with a 204 or with a 588 short HTML document. In addition to the `img` tag, websites may use 589 `style`, `script` and other tags to track usage. 590 * CORB won't impact these techniques, as they don't depend on the actual 591 content being returned by the HTTP server. This also applies to other 592 web features that don't care about the response: beacons, pings, CSP 593 violation reports, etc. 594 595* **Service workers** 596 * Service workers may intercept cross-origin requests and artificially 597 construct a response *within* the service worker (i.e. without crossing 598 origins and/or security boundaries). CORB will not block such responses. 599 * When service workers cache actual cross-origin responses (e.g. in 'no-cors' 600 request mode), the responses are 'opaque' and therefore CORB can block such 601 responses without changing the service worker's behavior ('opaque' responses 602 have a non-accessible body even without CORB). 603 604* **Blob and File API** 605 * Fetching cross-origin blob URLs is blocked even without CORB 606 (see https://github.com/whatwg/fetch/issues/666). 607 * WPT test: `script-html-via-cross-origin-blob-url.sub.html` 608 (and also tests for navigation requests covered by the 609 [commit here](https://github.com/mkruisselbrink/web-platform-tests/commit/9524a71919340eacc8aaa6e55ffe0b5aa72f9bfd)). 610 611* **Content scripts and plugins** 612 * These are not covered by CORB - CORB assumes that that appropriate security 613 policies are enforced by some other mechanism for content scripts and 614 plugins (e.g. Adobe Flash implements a CORS-like mechanism via 615 [crossdomain.xml](https://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html)). 616 617### Quantifying CORB impact on existing websites 618 619CORB has been enabled in optional Site Isolation modes and field trials, and 620Chromium has been instrumented to count how many CORB-eligible responses are 621blocked. (CORB-eligible responses exclude 622[navigation requests](https://fetch.spec.whatwg.org/#navigation-request) and 623downloads; see the "What kinds of requests are CORB-eligible?" section above.) 624Our analysis of the initial data from Chrome Canary in February 2018 shows a low 625upper bound on the number of cases observable to web pages, with possibilities 626to further lower the bounds. 627 628Overall, **0.961% of all CORB-eligible responses are blocked.** However, over 629half of these are empty responses already (i.e., actually have a 630`Content-Length: 0` response header), and thus cause effectively no behavior 631change (i.e., only 632[non-safelisted](https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name) 633headers would be affected). Note that if sniffing were omitted, almost 20% of 634responses would be blocked, so sniffing is a clear necessity. 635 636Looking closer, **0.456% of all CORB-eligible responses are non-empty and 637blocked.** However, most of these cases fall into the non-observable categories 638described in the subsections above, such as HTML responses being delivered to 639image tags as tracking pixels. 640 641We can focus on two groups of blocked responses which may have observable 642impact. 643 644* **0.115% of all CORB-eligible responses might have been observably blocked due 645 to a nosniff header or range request.** This is specific to non-empty 646 responses with a status code other than 204, requested from a context that 647 doesn't otherwise ignore mislabeled nosniff content (e.g., as script tags 648 would). Within this group: 649 * 95.16% of these are nosniff responses labeled as HTML requested by an image 650 tag. These are blocked and could possibly contain real images. However, we 651 expect many of these cases actually contained HTML and would not have 652 rendered in the image tag anyway (as we observed in one case). 653 654> [creis@chromium.org] We are considering lowering this bound further by 655> sniffing these responses to confirm how many might contain actual images. 656 657 * Another 3.76% of these are range requests for text/plain from a media 658 context. We have not yet found examples in practice, but we are considering 659 allowing range request responses for text/plain to avoid disruption here. 660 661* **0.014% of all CORB-eligible responses were invalid inputs to script tags**, 662 since CORB sniffing revealed they were HTML, XML, or JSON. Again, this is 663 specific to non-empty responses that do not have a 204 status code. These 664 cases should have minimal risk of disruption in practice (e.g., more than half 665 have error status codes and likely represent broken links), but it is 666 technically possible to observe a difference based on whether a syntax error 667 is reported. 668 669These numbers of affected cases are sufficiently low to suggest that CORB is 670promising from a web compatibility perspective. 671 672 673## Appendix: Future work - protecting more resource types 674 675The currently proposed version of CORB only protects JSON, HTML and XML 676resources - other sensitive resources need to be protected in some other way. 677One possible approach is to protect such resources via unguessable XSRF tokens 678which are distributed via JSON (which is CORB-protected). 679 680In the future CORB may be extended to protect additional resources as follows: 681 682* **Covering more MIME types**. 683 Instead of blacklisting HTML, XML, and JSON, CORB protection can be extended to 684 all MIME types, except MIME types that are whitelisted as usable in `<img>`, 685 `<audio>`, `<video>`, `<script>` and other similar elements that can be 686 embedded cross-origin: 687 * [JavaScript MIME type](https://html.spec.whatwg.org/#javascript-mime-type) 688 like `text/javascript`, `application/javascript`, or `text/jscript` 689 * `text/css` 690 * [image types](https://mimesniff.spec.whatwg.org/#image-type) like types 691 matching `image/*` 692 * [audio or video types](https://mimesniff.spec.whatwg.org/#audio-or-video-type) 693 like `audio/*`, `video/*` or `application/ogg` 694 * `font/*` or one of legacy 695 [font types](https://mimesniff.spec.whatwg.org/#font-type) 696 * Other MIME types like 697 `application/octet-stream`, 698 [text/vtt](https://w3c.github.io/webvtt/#file-structure) 699 700 This extension would offer CORB-protection to resources like PDFs or ZIP files. 701 CORB would not perform confirmation sniffing for MIME types other than HTML, 702 XML and JSON (since it is not practical to teach CORB sniffer about *all* the 703 possible MIME types). On the other hand, the value of confirmation sniffing 704 for these other MIME types seems low, since mislabeling content as such 705 types seems less likely than for example mislabeling as `text/html`. 706 707> [lukasza@chromium.org] See also https://github.com/whatwg/fetch/issues/721 708 709* **CORB opt-in header**. 710 To protect resources that normally may be embedded cross-origin, 711 a server might explicitly opt into CORB with a HTTP response header. 712 This would make it possible to CORB-protect resources like 713 images or JavaScript (including JSONP). 714 715> [lukasza@chromium.org] Currently considered CORB opt-in signals include: 716> - `From-Origin:` or `Cross-Origin-Resource-Policy:` header - see https://github.com/whatwg/fetch/issues/687 717> - `Isolate-Me` header - see https://github.com/WICG/isolation 718 719## Appendix: CORB and web standards 720 721[The CORB section in the Fetch spec](https://fetch.spec.whatwg.org/#corb) covers 722handling of `nosniff` and 206 responses since 723[May 2018](https://github.com/whatwg/fetch/pull/686). 724 725CORB confirmation sniffing is not standardized yet. 726 727[Some aspects of CORB](https://github.com/whatwg/fetch/issues?utf8=%E2%9C%93&q=is%3Aissue+CORB+) 728are under discussion and may evolve over time. 729 730## Appendix: CORB implementation status 731 732Tracking bugs: 733- Chrome: https://crbug.com/268640 and https://crbug.com/802835 and https://www.chromestatus.com/feature/5629709824032768 734- Edge: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/17382911/ 735- Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1459357 736- Safari/WebKit: https://bugs.webkit.org/show_bug.cgi?id=185331 737 738Status of Web Platform Tests: 739- [Experimental builds](https://master-dot-wptdashboard.appspot.com/results/fetch/corb?label=experimental) 740- [Stable releases](https://master-dot-wptdashboard.appspot.com/results/fetch/corb) 741