diff --git a/fetch.bs b/fetch.bs index 18ff28f7c..f0c89059b 100644 --- a/fetch.bs +++ b/fetch.bs @@ -53,6 +53,9 @@ urlPrefix:https://tc39.es/ecma262/#;type:dfn;spec:ecma-262 url:realm;text:realm url:sec-list-and-record-specification-type;text:Record url:current-realm;text:current realm + url:sec-parsetext;text:ParseText + url:prod-Script;text:Script + url:script-record;text:Script Record
@@ -2161,6 +2164,17 @@ Unless stated otherwise, it is false.This flag is for exclusive use by HTML's render-blocking mechanism. [[!HTML]] +
A request has an associated +no-cors media request state ... + +
This is for exclusive use by the opaque-response-safelist check. + +
A request has an associated +no-cors JavaScript fallback encoding (an encoding). Unless +stated otherwise, it is UTF-8. + +
This is for exclusive use by the opaque-response-safelist check. +
A request has an associated @@ -3275,6 +3289,370 @@ through TLS using ALPN. The protocol cannot be spoofed through HTTP requests in +
Opaque-response blocking
+ +++ + +Opaque-response blocking, also known as ORB, is a network filter that blocks access + to opaque filtered responses. These responses would likely would not have been useful to the + fetching party. Blocking them reduces information leakage to potential attackers. + +
Essentially, CSS, JavaScript, images, and media (audio and video) can be requested across + origins without the CORS protocol. And unfortunately except for CSS there is no MIME type + enforcement. This algorithm aims to block as many responses as possible that are not one of these + types (or are newer variants of those types) to avoid leaking their contents through side channels. + +
The network filter combines pro-active blocking based on response headers, sniffing a limited + set of bytes, and ultimately falls back to a full parse due to unfortunate (lack of) design + decisions in the early days of the web platform. As a result there are still quite a few responses + whose secrets can end up being revealed to attackers. Web developers are strongly encouraged to use + the `
Cross-Origin-Resource-Policy
` response header to defend them. +The opaque-response-safelist check
+ +The opaque-response-safelist check, given a request request +and a response response, is to run these steps: + +
+
+ +Let mimeType be the result of extracting a MIME type from + response's header list. + +
Let nosniff be the result of determining nosniff given + response's header list. + +
- +
If mimeType is not failure, then: + +
+
+ +If mimeType is an opaque-response-safelisted MIME type, then return + true. + +
If mimeType is an opaque-response-blocklisted-never-sniffed MIME type, + then return false. + +
If response's status is 206 and mimeType is an + opaque-response-blocklisted MIME type, then return false. + +
If nosniff is true and mimeType's essence is + "
text/plain
", then return false. +If request's no-cors media request state is + "
subsequent
", then return true. + +If response's status is 206 and + validate a partial response given 0 and response returns invalid, then return + false. + +
Let bytes be the result of running + obtain a copy of the first 1024 bytes of response given response. + +
If bytes is failure, then return false. + +
- +
If the audio or video type pattern matching algorithm given bytes does not + return undefined, then: + +
+
+ +If requests's no-cors media request state is not + "
initial
", then return false. + +If response's status is not 200 or 206, then return false. + +
Return true. +
If requests's no-cors media request state is not + "
N/A
", then return false. + +If the image type pattern matching algorithm given bytes does not return + undefined, then return true. + +
- +
If nosniff is true, then return false. + +
This check is made late as unfortunately images and media are always sniffed. + +
If response's status is not an ok status, then return + false. + +
- +
If mimeType is failure, then return true. + +
This could be improved at somewhat significant cost. See + annevk/orb #28. + +
If mimeType's essence starts with + "
audio/
", "image/
", or "video/
", then return false. + +Return determine if response is JavaScript and not JSON given response. +
+ +++ +To extract content-range values, given a response response +run these steps:
+ ++
+ +If response’s header list does not contain `
Content-Range
`, then return failure. + +Let contentRangeValue be the value of the first header whose name is a + byte-case-insensitive match for `
Content-Range
` in response’s header list. + +If parsing contentRangeValue per single byte content-range fails, then return failure. + +
Let firstBytePos be the portion of contentRangeValue named + first-byte-pos when parsed as single byte content-range, parsed as an integer. + +
Let lastBytePos be the portion of contentRangeValue named + last-byte-pos when parsed as single byte content-range, parsed as an integer. + +
Let completeLength be the portion of contentRangeValue named + complete-length when parsed as single byte content-range. + +
If completeLength is "
*
", then set completeLength to null, otherwise + set completeLength to completeLength parsed as an integer. + +Return firstBytePos, lastBytePos, and completeLength. +
Parsing as an integer infra/189 +
+ +++ +To validate a partial response, given an integer expectedRangeStart , a +response partialResponse, and an optional response previousResponse (default null), +run these steps:
+ ++
+Assert: partialResponse's status is `206`. + +
Let responseFirstBytePos, responseLastBytePos, and responseCompleteLength be the + result of extracting content-range values from partialResponse. If this fails, then return invalid. + +
If responseFirstBytePos does not equal expectedRangeStart, then return invalid. + +
If previousResponse is not null, then: + +
+
+For headerName of « `
ETag
`, `Last-Modified
` »: + ++
+ +- If previousResponse's header list contains headerName + and the combined value of headerName + in previousResponse's header list does not equal the + combined value of headerName in partialResponse's + header list, then return invalid. +
If previousResponse's status is 206, then: + +
+
+Let previousResponseFirstBytePos, previousResponseLastBytePos, + and previousResponseCompleteLength be the result of extracting content-range values + from previousResponse. If this fails, then return invalid. + +
If previousResponseCompleteLength is not null, and + responseCompleteLength does not equal previousResponseCompleteLength, then return invalid. +
- Return valid. +
+ +++ +To obtain a copy of the first 1024 bytes of response, given a response +response, run these steps: + +
+
+Let first1024Bytes be null. + +
- +
In parallel: + +
+
+ +Let bytes be the empty byte sequence. + +
Let transformStream be a new {{TransformStream}}. + +
- +
Let transformAlgorithm given a chunk be these steps: + +
+
+ +Enqueue chunk in transformStream. + +
- +
If first1024Bytes is null, then: + +
+
+Let chunkBytes be + a copy of the bytes held by + chunk. + +
Append chunkBytes to bytes. + +
- +
If bytes's length is greater than 1024, then: + +
+
+Truncate bytes from the end so that it only contains 1024 bytes. + +
Set first1024Bytes to bytes. +
Let flushAlgorithm be this step: if first1024Bytes is null, then set + first1024Bytes to bytes. + +
Set up transformStream with + transformAlgorithm set to + transformAlgorithm and flushAlgorithm set + to flushAlgorithm. + +
Set response's body's stream to the result + of response's body's stream + piped through transformStream. +
Wait until first1024Bytes is non-null or response's + body's stream is errored. + +
If first1024Bytes is null, then return failure. + +
- Return first1024Bytes. +
+ +++ + +To determine if response is JavaScript and not JSON, given a request request, +a response response, run these steps:
+ ++
+Let responseBodyBytes be null. + +
- +
Let processBody given a byte sequence bytes be these steps: + +
+
+ +Set responseBodyBytes to bytes. + +
Set response's body to the body + of the result of safely extracting bytes. +
Let processBodyError be this step: set responseBodyBytes to failure. + +
Fully read response's body given processBody + and processBodyError. + +
Wait for responseBodyBytes to be non-null. + +
If responseBodyBytes is failure, then return false. + +
Assert: responseBodyBytes is a byte sequence. + +
- +
If parse JSON bytes to a JavaScript value given responseBodyBytes does not + throw, then return false. If it throws, catch the exception and ignore it. + +
If there is an exception, response is not JSON. If there is not, it is. + +
Let potentialMIMETypeForEncoding be the result of extracting a MIME type + given response's header list. + +
- +
Let encoding be the result of legacy extract an encoding given + potentialMIMETypeForEncoding and request's + no-cors JavaScript fallback encoding. + +
Equivalently to fetch a classic script, this ignores the + MIME type essence. + +
Let sourceText be the result of decoding + responseBodyBytes given encoding. + +
If ParseText(sourceText, Script) returns a Script Record, + then return true. + + +
Return false. +
New MIME type sets
+ +The definitions in this section are solely for the purpose of abstracting parts of the +opaque-response-safelist check. They are not suited for usage elsewhere. + +
An opaque-response-safelisted MIME type is a JavaScript MIME type or a +MIME type whose essence is "
text/css
" or +"image/svg+xml
". + +An opaque-response-blocklisted MIME type is an HTML MIME type, +JSON MIME type, or XML MIME type. + +
An opaque-response-blocklisted-never-sniffed MIME type is a MIME type +whose essence is one of: + +
application/dash+xml
"
+ application/gzip
"
+ application/msexcel
"
+ application/mspowerpoint
"
+ application/msword
"
+ application/msword-template
"
+ application/pdf
"
+ application/vnd.apple.mpegurl
"
+ application/vnd.ces-quickpoint
"
+ application/vnd.ces-quicksheet
"
+ application/vnd.ces-quickword
"
+ application/vnd.ms-excel
"
+ application/vnd.ms-excel.sheet.macroenabled.12
"
+ application/vnd.ms-powerpoint
"
+ application/vnd.ms-powerpoint.presentation.macroenabled.12
"
+ application/vnd.ms-word
"
+ application/vnd.ms-word.document.12
"
+ application/vnd.ms-word.document.macroenabled.12
"
+ application/vnd.msword
"
+ application/vnd.openxmlformats-officedocument.presentationml.presentation
"
+ application/vnd.openxmlformats-officedocument.presentationml.template
"
+ application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
"
+ application/vnd.openxmlformats-officedocument.spreadsheetml.template
"
+ application/vnd.openxmlformats-officedocument.wordprocessingml.document
"
+ application/vnd.openxmlformats-officedocument.wordprocessingml.template
"
+ application/vnd.presentation-openxml
"
+ application/vnd.presentation-openxmlm
"
+ application/vnd.spreadsheet-openxml
"
+ application/vnd.wordprocessing-openxml
"
+ application/x-gzip
"
+ application/x-protobuf
"
+ application/x-protobuffer
"
+ application/zip
"
+ audio/aac
"
+ audio/aacp
"
+ audio/mpegurl
"
+ audio/mpeg
"
+ multipart/byteranges
"
+ multipart/signed
"
+ multipart/x-mixed-replace
"
+ text/event-stream
"
+ text/csv
"
+ text/vtt
"
+*
` coun
requests without credentials. For such requests there is no
way to solely match a header name or method that is `*
`.
+ABNF for a single byte content-range: + +
+"bytes=" first-byte-pos "-" last-byte-pos "/" complete-length
+first-byte-pos = 1*DIGIT
+last-byte-pos = 1*DIGIT
+complete-length = ( 1*DIGIT / "*" )
+
+
+This is a subset of what RFC 7233 allows. + +
+ T: "bytes=" + Stack: + Sequence: + Comment: first-byte-pos + OneOrMore: + N: digit + Comment: /first-byte-pos + N: "/" + Sequence: + Comment: last-byte-pos + OneOrMore: + N: digit + Comment: /last-byte-pos + N: "/" + Sequence: + Comment: complete-length + Choice: + N: "*" + OneOrMore: + N: digit + Comment: /complete-length ++
Set response and internalResponse to the result of running HTTP-network-or-cache fetch given fetchParams. -
If request's response tainting is "cors
" and a
- CORS check for request and response returns failure, then return a
- network error.
+
If request's response tainting is "opaque
",
+ response's status is not a redirect status, then
+
+
If request's initiator type is "fetch
",
+ then set internalResponse's body to null.
-
As the CORS check is not to be applied to responses whose - status is 304 or 407, or responses from a service worker for - that matter, it is applied here. +
Otherwise, if opaque-response-safelist check given request and response returns + false, then return a network error. +
If request's response tainting is "cors
" and
+ the CORS check for request and response returns failure, then return
+ a network error.
If the TAO check for request and response returns failure, then set request's timing allow failed flag. +
As the opaque-response-safelist check, CORS check, and + TAO check are not to be applied to responses whose status + is 304 or 407, or to responses from a service worker, they are applied here. +
If either request's response tainting or response's
type is "opaque
", and the
@@ -9152,6 +9579,7 @@ Mohamed Zergaoui,
Mohammed Zubair Ahmed,
Moritz Kneilmann,
Ms2ger,
+Nathan Froyd,
Nico Schlömer,
Nicolás Peña Moreno,
Nidhi Jaju,