Skip to content

Commit 6194d0f

Browse files
committed
Define opaque-response blocking
This is good enough for early review, but there are a number of issues that still need resolving: https://github.com/annevk/orb/labels/mvp. There are also some inline TODO comments. A PR against HTML is needed to ensure it passes the appropriate metadata for media element and classic script requests. We might also want to depend on HTML for parsing JavaScript.
1 parent 78f9bdd commit 6194d0f

File tree

1 file changed

+216
-1
lines changed

1 file changed

+216
-1
lines changed

fetch.bs

+216-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ urlPrefix:https://w3c.github.io/hr-time/#;spec:hr-time
3333
url:dfn-coarsened-shared-current-time;text:coarsened shared current time
3434
url:dfn-unsafe-shared-current-time;text:unsafe shared current time
3535
type:typedef;url:dom-domhighrestimestamp;text:DOMHighResTimeStamp
36+
37+
urlPrefix: https://tc39.es/ecma262/;type:dfn;spec:ecma-262
38+
url:sec-parsetext;text:ParseText
39+
url:prod-Script;text:Script
40+
url:script-record;text:Script Record
3641
</pre>
3742

3843
<pre class=link-defaults>
@@ -1844,6 +1849,17 @@ Unless stated otherwise, it is false.
18441849

18451850
<p class=note>This flag is for exclusive use by HTML's render-blocking mechanism. [[!HTML]]
18461851

1852+
<p class=XXX>A <a for=/>request</a> has an associated
1853+
<dfn export for=request>no-cors media request state</dfn> ...
1854+
1855+
<p class=note>This is for exclusive use by the <a>opaque-response-safelist check</a>.
1856+
1857+
<p>A <a for=/>request</a> has an associated
1858+
<dfn for=request>no-cors JavaScript fallback encoding</dfn> (an <a for=/>encoding</a>). Unless
1859+
stated otherwise, it is <a for=/>UTF-8</a>.
1860+
1861+
<p class=note>This is for exclusive use by the <a>opaque-response-safelist check</a>.
1862+
18471863
<hr>
18481864

18491865
<p>A <a for=/>request</a> has an associated
@@ -2876,6 +2892,198 @@ run these steps:
28762892
</ol>
28772893

28782894

2895+
<h3 id=orb>Opaque-response blocking</h3>
2896+
2897+
<div class=note>
2898+
<p>Opaque-response blocking, also known as <abbr>ORB</abbr>, is a network filter that blocks access
2899+
to <a>opaque filtered responses</a>. These responses would likely would not have been useful to the
2900+
fetching party. Blocking them reduces information leakage to potential attackers.
2901+
2902+
<p>Essentially, CSS, JavaScript, images, and media (audio and video) can be requested across
2903+
origins without the <a>CORS protocol</a>. And unfortunately except for CSS there is no MIME type
2904+
enforcement. This algorithm aims to block as many responses as possible that are not one of these
2905+
types (or are newer variants of those types) to avoid leaking their contents through side channels.
2906+
2907+
<p>The network filter combines pro-active blocking based on response headers, sniffing a limited
2908+
set of bytes, and ultimately falls back to a full parse due to unfortunate (lack of) design
2909+
decisions in the early days of the web platform. As a result there are still quite a few responses
2910+
whose secrets can end up being revealed to attackers. Web developers are strongly encouraged to use
2911+
the `<code http-header>Cross-Origin-Resource-Policy</code>` response header to defend them.
2912+
</div>
2913+
2914+
2915+
<h4 id=orb-algorithm>The opaque-response-safelist check</h4>
2916+
2917+
<p>The <dfn>opaque-response-safelist check</dfn>, given a <a for=/>request</a> <var>request</var>
2918+
and a <a for=/>response</a> <var>response</var>, is to run these steps:
2919+
2920+
<ol>
2921+
<li><p>Let <var>mimeType</var> be the result of <a>extracting a MIME type</a> from
2922+
<var>response</var>'s <a for=response>header list</a>.
2923+
2924+
<li><p>Let <var>nosniff</var> be the result of <a>determining nosniff</a> given
2925+
<var>response</var>'s <a for=response>header list</a>.
2926+
2927+
<li>
2928+
<p>If <var>mimeType</var> is not failure, then:
2929+
2930+
<ol>
2931+
<li><p>If <var>mimeType</var> is an <a>opaque-response-safelisted MIME type</a>, then return
2932+
true.
2933+
2934+
<li><p>If <var>mimeType</var> is an <a>opaque-response-blocklisted-never-sniffed MIME type</a>,
2935+
then return false.
2936+
2937+
<li><p>If <var>response</var>'s <a for=response>status</a> is 206 and <var>mimeType</var> is an
2938+
<a>opaque-response-blocklisted MIME type</a>, then return false.
2939+
2940+
<li><p>If <var>nosniff</var> is true and <var>mimeType</var> is an
2941+
<a>opaque-response-blocklisted MIME type</a> or its <a for="MIME type">essence</a> is
2942+
"<code>text/plain</code>", then return false.
2943+
</ol>
2944+
2945+
<li><p>If <var>request</var>'s <a for=request>no-cors media request state</a> is
2946+
"<code>subsequent</code>", then return true.
2947+
2948+
<li><p>If <var>response</var>'s <a for=response>status</a> is 206 and
2949+
<a>validate a partial response</a> given 0 and <var>response</var> returns invalid, then return
2950+
false.
2951+
<!-- TODO Integrate https://wicg.github.io/background-fetch/#validate-a-partial-response into Fetch -->
2952+
2953+
<li><p>Wait for 1024 bytes of <var>response</var>'s <a for=response>body</a> or end-of-file,
2954+
whichever comes first and let <var>bytes</var> be those bytes.
2955+
<!-- TODO Obtaining these bytes needs to be defined in terms of a transform stream. -->
2956+
2957+
<li>
2958+
<p>If the <a>audio or video type pattern matching algorithm</a> given <var>bytes</var> does not
2959+
return undefined, then:
2960+
2961+
<ol>
2962+
<li><p>If <var>requests</var>'s <a for=request>no-cors media request state</a> is not
2963+
"<code>initial</code>", then return false.
2964+
2965+
<li><p>If <var>response</var>'s <a for=response>status</a> is not 200 or 206, then return false.
2966+
2967+
<li><p>Return true.
2968+
</ol>
2969+
2970+
<li><p>If <var>requests</var>'s <a for=request>no-cors media request state</a> is not
2971+
"<code>N/A</code>", then return false.
2972+
2973+
<li><p>If the <a>image type pattern matching algorithm</a> given <var>bytes</var> does not return
2974+
undefined, then return true.
2975+
2976+
<li>
2977+
<p>If <var>nosniff</var> is true, then return false.
2978+
2979+
<p class=note>This check is made late as unfortunately images and media are always sniffed.
2980+
2981+
<li><p>If <var>response</var>'s <a for=response>status</a> is not an <a>ok status</a>, then return
2982+
false.
2983+
2984+
<li>
2985+
<p>If <var>mimeType</var> is failure, then return true.
2986+
2987+
<p class=note>This could be improved at somewhat significant cost. See
2988+
<a href=https://github.com/annevk/orb/issues/28>annevk/orb #28</a>.
2989+
2990+
<li><p>If <var>mimeType</var>'s <a for="MIME type">essence</a> <a for=string>starts with</a>
2991+
"<code>audio/</code>", "<code>image/</code>", or "<code>video/</code>", then return false.
2992+
2993+
<li><p>Let <var>responseBodyBytes</var> be null.
2994+
2995+
<li>
2996+
<p>Let <var>processBody</var> given a <a for=/>byte sequence</a> <var>bytes</var> be these steps:
2997+
2998+
<ol>
2999+
<li><p>Set <var>responseBodyBytes</var> to <var>bytes</var>.
3000+
3001+
<li><p>Set <var>response</var>'s <a for=response>body</a> to the <a for="body with type">body</a>
3002+
of the result of <a for=BodyInit>safely extracting</a> <var>bytes</var>.
3003+
</ol>
3004+
3005+
<li><p>Let <var>processBodyError</var> be this step: set <var>responseBodyBytes</var> to failure.
3006+
3007+
<li><p><a>Fully read</a> <var>response</var>'s <a for=response>body</a> given <a>processBody</a>
3008+
and <var>processBodyError</var>.
3009+
3010+
<li><p>Wait for <var>responseBodyBytes</var> to be non-null.
3011+
3012+
<li><p>If <var>responseBodyBytes</var> is failure, then return false.
3013+
3014+
<li><p><a for=/>Assert</a>: <var>responseBodyBytes</var> is a <a for=/>byte sequence</a>.
3015+
3016+
<li><p>If <a>parse JSON bytes to a JavaScript value</a> given <var>responseBodyBytes</var> does not
3017+
throw, then return false. If it throws, catch the exception and ignore it.
3018+
3019+
<li><p>Let <var>sourceText</var> be the result of <a for=/>decoding</a>
3020+
<var>responseBodyBytes</var> given <var>request</var>'s
3021+
<a for=request>no-cors JavaScript fallback encoding</a>.
3022+
3023+
<li><p>If <a>ParseText</a>(<var>sourceText</var>, <a>Script</a>) returns a <a>Script Record</a>,
3024+
then return true.
3025+
<!-- Ideally HTML owns this so ECMAScript changes don't end up impacting Fetch. We could
3026+
potentially make this use "create a classic script" instead with some mock data. Maybe that is
3027+
better? -->
3028+
3029+
<li><p>Return false.
3030+
</ol>
3031+
3032+
3033+
<h4 id=orb-mime-type-sets>New MIME type sets</h4>
3034+
3035+
<p class=note>The definitions in this section are solely for the purpose of abstracting parts of the
3036+
<a>opaque-response-safelist check</a>. They are not suited for usage elsewhere.
3037+
3038+
<p>An <dfn>opaque-response-safelisted MIME type</dfn> is a <a>JavaScript MIME type</a> or a
3039+
<a for=/>MIME type</a> whose <a for="MIME type">essence</a> is "<code>text/css</code>" or
3040+
"<code>image/svg+xml</code>".
3041+
3042+
<p>An <dfn>opaque-response-blocklisted MIME type</dfn> is an <a>HTML MIME type</a>,
3043+
<a>JSON MIME type</a>, or <a>XML MIME type</a>.
3044+
3045+
<p>An <dfn>opaque-response-blocklisted-never-sniffed MIME type</dfn> is a <a for=/>MIME type</a>
3046+
whose <a for="MIME type">essence</a> is one of:
3047+
3048+
<ul class=brief>
3049+
<li>"<code>application/gzip</code>"
3050+
<li>"<code>application/msexcel</code>"
3051+
<li>"<code>application/mspowerpoint</code>"
3052+
<li>"<code>application/msword</code>"
3053+
<li>"<code>application/msword-template</code>"
3054+
<li>"<code>application/pdf</code>"
3055+
<li>"<code>application/vnd.ces-quickpoint</code>"
3056+
<li>"<code>application/vnd.ces-quicksheet</code>"
3057+
<li>"<code>application/vnd.ces-quickword</code>"
3058+
<li>"<code>application/vnd.ms-excel</code>"
3059+
<li>"<code>application/vnd.ms-excel.sheet.macroenabled.12</code>"
3060+
<li>"<code>application/vnd.ms-powerpoint</code>"
3061+
<li>"<code>application/vnd.ms-powerpoint.presentation.macroenabled.12</code>"
3062+
<li>"<code>application/vnd.ms-word</code>"
3063+
<li>"<code>application/vnd.ms-word.document.12</code>"
3064+
<li>"<code>application/vnd.ms-word.document.macroenabled.12</code>"
3065+
<li>"<code>application/vnd.msword</code>"
3066+
<li>"<code>application/vnd.openxmlformats-officedocument.presentationml.presentation</code>"
3067+
<li>"<code>application/vnd.openxmlformats-officedocument.presentationml.template</code>"
3068+
<li>"<code>application/vnd.openxmlformats-officedocument.spreadsheetml.sheet</code>"
3069+
<li>"<code>application/vnd.openxmlformats-officedocument.spreadsheetml.template</code>"
3070+
<li>"<code>application/vnd.openxmlformats-officedocument.wordprocessingml.document</code>"
3071+
<li>"<code>application/vnd.openxmlformats-officedocument.wordprocessingml.template</code>"
3072+
<li>"<code>application/vnd.presentation-openxml</code>"
3073+
<li>"<code>application/vnd.presentation-openxmlm</code>"
3074+
<li>"<code>application/vnd.spreadsheet-openxml</code>"
3075+
<li>"<code>application/vnd.wordprocessing-openxml</code>"
3076+
<li>"<code>application/x-gzip</code>"
3077+
<li>"<code>application/x-protobuf</code>"
3078+
<li>"<code>application/x-protobuffer</code>"
3079+
<li>"<code>application/zip</code>"
3080+
<li>"<code>multipart/byteranges</code>"
3081+
<li>"<code>multipart/signed</code>"
3082+
<li>"<code>text/event-stream</code>"
3083+
<li>"<code>text/csv</code>"
3084+
</ul>
3085+
3086+
28793087

28803088
<h2 id=http-extensions>HTTP extensions</h2>
28813089

@@ -4081,8 +4289,14 @@ steps:
40814289

40824290
<li><p>Set <var>request</var>'s <a for=request>response tainting</a> to "<code>opaque</code>".
40834291

4084-
<li><p>Return the result of running <a>scheme fetch</a> given <var>fetchParams</var>.
4292+
<li><p>Let <var>opaqueResponse</var> be the result of running <a>scheme fetch</a> given
4293+
<var>fetchParams</var>.
40854294
<!-- file URLs end up here as they are not same-origin typically. -->
4295+
4296+
<li><p>If the <a>opaque-response-safelist check</a> given <var>request</var> and
4297+
<var>opaqueResponse</var> returns true, then return <var>opaqueResponse</var>.
4298+
4299+
<li><p>Return a <a>network error</a>.
40864300
</ol>
40874301

40884302
<dt><var>request</var>'s <a for=request>current URL</a>'s <a for=url>scheme</a> is not an
@@ -8346,6 +8560,7 @@ Mohamed Zergaoui,
83468560
Mohammed Zubair Ahmed<!-- M-ZubairAhmed; GitHub -->,
83478561
Moritz Kneilmann,
83488562
Ms2ger,
8563+
Nathan Froyd,
83498564
Nico Schlömer,
83508565
Nicolás Peña Moreno,
83518566
Nikhil Marathe,

0 commit comments

Comments
 (0)