Skip to content

Commit f1728a1

Browse files
committed
Better explanation of subresource headers.
This patch drops 'Content-Disposition', and aims to do a better job explaining the set of headers which seem valuable for subresources generally. Closes w3c#1.
1 parent 7ee71bb commit f1728a1

File tree

2 files changed

+232
-68
lines changed

2 files changed

+232
-68
lines changed

index.bs

Lines changed: 93 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,21 @@ Boilerplate: omit conformance
1414
Markup Shorthands: css off, markdown on
1515
</pre>
1616
<pre class="anchors">
17-
urlPrefix: https://html.spec.whatwg.org/; spec: HTML; type: dfn
18-
text: origin; url: multipage/origin.html#concept-origin
19-
text: cross-origin opener policy; url: multipage/origin.html#cross-origin-opener-policies
20-
text: cross-origin embedder policy; url: multipage/origin.html#coep
17+
urlPrefix: https://html.spec.whatwg.org/; spec: HTML;
18+
type: dfn
19+
text: origin; url: multipage/origin.html#concept-origin
20+
text: cross-origin opener policy; url: multipage/origin.html#cross-origin-opener-policies
21+
text: cross-origin embedder policy; url: multipage/origin.html#coep
22+
type: http-header
23+
text: cross-origin-opener-policy; url: multipage/origin.html#cross-origin-opener-policies
24+
text: x-frame-options; url: multipage/browsing-the-web.html#the-x-frame-options-header
2125
urlPrefix: https://fetch.spec.whatwg.org/; spec: FETCH; type: dfn
2226
text: cross-origin resource policy; url: #http-cross-origin-resource-policy
2327
text: cross-origin read blocking; url: #corb
2428
urlPrefix: https://tc39.es/ecma262/; spec: ECMA262; type: interface
2529
text: SharedArrayBuffer; url: #sec-sharedarraybuffer-objects
30+
urlPrefix: https://tools.ietf.org/html/rfc7231; spec: RFC7231; type: http-header
31+
text: Vary; url: #section-7.1.4
2632
</pre>
2733
<pre class="biblio">
2834
{
@@ -248,6 +254,57 @@ Practical Examples {#examples}
248254
Subresources {#subresources}
249255
----------------------------
250256

257+
Resources which are intended to be loaded into documents should protect themselves from being used
258+
in unexpected ways. Before walking through strategies for specific kinds of resources, a few headers
259+
seem generally applicable:
260+
261+
1. Sites should use Fetch Metadata to make good decisions about when to serve resources, as
262+
described in [[resource-isolation-policy]]. In order to ensure that decision sticks, servers
263+
should explain its decision to the browser by sending a <a http-header>`Vary`</a> header
264+
containing `Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site`. This ensures that the server has
265+
a chance to make different decisions for requests which will be *used* differently.
266+
267+
2. Subresources should opt-out of MIME type sniffing by sending an
268+
<a http-header>`X-Content-Type-Options`</a> header with a value of `nosniff`. This increases the
269+
robustness of MIME-based checks like [=cross-origin read blocking=] (CORB) /
270+
<a href="https://github.com/annevk/orb">opaque response blocking</a> ([[ORB]]), and mitigates
271+
some well-known risks around type confusion for scripts.
272+
273+
3. Subresources are intended for inclusion in a given context, not as independently navigable
274+
documents. To mitigate the risk that navigation to a subresource causes script execution or
275+
opens an origin up to attack in some other way, servers can assert the following set of headers
276+
which collectively make it difficult to meaningfully abuse a subresource via navigation:
277+
278+
* Using the <a http-header>`Content-Security-Policy`</a> header's to assert the
279+
<a>`sandbox`</a> directive ensures that these resources remain inactive if navigated to
280+
directly as a top-level document. No scripts will execute, and the resource will be pushed
281+
into an [=opaque origin=].
282+
283+
Note: Some servers deliver `Content-Disposition: attachment; filename=file.name` to obtain
284+
a similar effect. This was valuable to mitigate vulnerabilies in Flash, but the sandbox
285+
approach seems to more straightforwardly address the threats we care about today.
286+
287+
* Asserting the <a http-header>`Cross-Origin-Opener-Policy`</a> header with a value of
288+
`same-origin` prevents cross-origin documents from retaining a handle to the resource's
289+
window if it's opened in a popup.
290+
291+
* The <a http-header>`X-Frame-Options`</a> header with a value of `DENY` prevents the resource
292+
from being framed.
293+
294+
Most subresources, then, should contain the following block of headers, which you'll see repeated a
295+
few times below:
296+
297+
<pre highlight="http">
298+
Content-Security-Policy: sandbox
299+
Cross-Origin-Opener-Policy: same-origin
300+
Vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site
301+
X-Content-Type-Options: nosniff
302+
X-Frame-Options: DENY
303+
</pre>
304+
305+
With these generic protections in mind, let's sift through a few scenarios to determine what headers
306+
a server would be well-served to assert:
307+
251308
### Static Subresources ### {#static-subresources}
252309

253310
By their nature, static resources contain the same data no matter who requests them, and therefore
@@ -256,16 +313,16 @@ to making these resources widely available, and value in allowing embedders to r
256313
something like the following response headers could be appropriate:
257314

258315
<pre highlight="http">
259-
Access-Control-Allow-Origin: *
316+
<strong>Access-Control-Allow-Origin: *
260317
Cross-Origin-Resource-Policy: cross-origin
261-
Timing-Allow-Origin: *
318+
Timing-Allow-Origin: *</strong>
319+
Content-Security-Policy: sandbox
320+
Cross-Origin-Opener-Policy: same-origin
321+
Vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site
262322
X-Content-Type-Options: nosniff
323+
X-Frame-Options: DENY
263324
</pre>
264325

265-
(Given these resources' characteristics, there's little risk in allowing them to be embedded in
266-
frames, but likely also little value. Unless there's a good reason to allow framing these
267-
subresources directly, consider also adding `X-Frame-Options: DENY`).
268-
269326
CDNs are the canonical static resource distribution points, and many use the pattern above. Take
270327
a look at the following common resources' response headers for inspiration:
271328

@@ -287,26 +344,21 @@ in question. A few cases are well worth considering:
287344

288345
1. Application-internal resources (private API endpoints, avatar images, uploaded data, etc.)
289346
should not be available to any cross-origin requestor. These resources should be restricted to
290-
usage as a subresource in same-origin contexts by sending the following headers:
347+
usage as a subresource in same-origin contexts by sending a
348+
<a http-header>`Cross-Origin-Resource-Policy`</a> header with a value of `same-origin`:
291349

292-
<pre class="lang-http">
350+
<pre highlight="http">
351+
<strong>Cross-Origin-Resource-Policy: same-origin</strong>
352+
Content-Security-Policy: sandbox
293353
Cross-Origin-Opener-Policy: same-origin
294-
Cross-Origin-Resource-Policy: same-origin
295-
Vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site
296-
X-Content-Type-Options: nosniff
297-
X-Frame-Options: DENY
298-
Content-Disposition: attachment; filename=file.name
354+
Vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site
355+
X-Content-Type-Options: nosniff
356+
X-Frame-Options: DENY
299357
</pre>
300358

301-
The most critical of these headers is `Cross-Origin-Resource-Policy: same-origin`, which will
302-
prevent attackers from loading this as a `no-cors` subresource in a cross-origin document.
303-
`X-Frame-Options` and `Cross-Origin-Opener-Policy` further restrict attackers' ability to frame
304-
this subresource, or open it in a window they might retain access to. `Content-Disposition`
305-
prevents some browsers from commiting this file as a document at all, prompting instead for
306-
permission to download the contents.
359+
This header will prevent cross-origin attackers from loading the resource as a response to a
360+
`no-cors` request.
307361

308-
ISSUE(mikewest/post-spectre-webdev#1): Does `Content-Disposition` make any sense?
309-
310362
For example, examine the headers returned when requesting endpoints like the following:
311363

312364
* <a href="https://myaccount.google.com/_/AccountSettingsUi/browserinfo">`https://myaccount.google.com/_/AccountSettingsUi/browserinfo`</a>
@@ -318,23 +370,24 @@ in question. A few cases are well worth considering:
318370
safely be enabled by requiring CORS, and choosing the set of origins for which a given response
319371
can be exposed by setting the appropriate access-control headers, for example:
320372

321-
<pre class="lang-http">
322-
Access-Control-Allow-Credentials: true
373+
<pre highlight="http">
374+
<strong>Access-Control-Allow-Credentials: true
323375
Access-Control-Allow-Origin: https://trusted.example
324376
Access-Control-Allow-Methods: POST
325377
Access-Control-Allow-Headers: ...
326378
Access-Control-Allow-...: ...
379+
Cross-Origin-Resource-Policy: same-origin</strong>
380+
Content-Security-Policy: sandbox
327381
Cross-Origin-Opener-Policy: same-origin
328-
Cross-Origin-Resource-Policy: same-origin
329382
Vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site
330383
X-Content-Type-Options: nosniff
331384
X-Frame-Options: DENY
332385
</pre>
333386

334387
Note: The `Cross-Origin-Resource-Policy` header is only processed for requests that are _not_
335388
using CORS for access control ("`no-cors` requests"). Sending
336-
`Cross-Origin-Resource-Policy: same-origin` is therefore not harmful, and working as a solid
337-
belts-and-suspenders approach to ensuring that `no-cors` usage isn't accidentally allowed.
389+
`Cross-Origin-Resource-Policy: same-origin` is therefore not harmful, and works to ensure that
390+
`no-cors` usage isn't accidentally allowed.
338391

339392
For example, examine the headers returned when requesting endpoints like the following:
340393

@@ -348,11 +401,13 @@ in question. A few cases are well worth considering:
348401
should enable cross-origin embedding via `Cross-Origin-Resource-Policy`, but _not_ via CORS
349402
access control headers:
350403

351-
<pre class="lang-http">
352-
Cross-Origin-Resource-Policy: cross-origin
404+
<pre highlight="http">
405+
<strong>Cross-Origin-Resource-Policy: cross-origin</strong>
406+
Content-Security-Policy: sandbox
407+
Cross-Origin-Opener-Policy: same-origin
408+
Vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site
353409
X-Content-Type-Options: nosniff
354410
X-Frame-Options: DENY
355-
Cross-Origin-Opener-Policy: same-origin
356411
</pre>
357412

358413
For example:
@@ -372,7 +427,7 @@ by making _a priori_ decisions about whether to serve the page at all (see
372427
the page can be used once delivered. For instance, something like the following set of response
373428
headers could be appropriate:
374429

375-
<pre class="lang-http">
430+
<pre highlight="http">
376431
Cross-Origin-Opener-Policy: same-origin
377432
Cross-Origin-Resource-Policy: same-origin
378433
Vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site
@@ -400,7 +455,7 @@ but they can't easily lock themselves off from all such vectors via
400455
`Cross-Origin-Opener-Policy: same-origin` and `X-Frame-Options: DENY`. In these cases, something
401456
like the following set of response headers might be appropriate:
402457

403-
<pre class="lang-http">
458+
<pre highlight="http">
404459
Cross-Origin-Opener-Policy: same-origin-allow-popups
405460
Cross-Origin-Resource-Policy: same-origin
406461
Vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site
@@ -427,7 +482,7 @@ or fetched cross-origin. Three scenarios are worth considering:
427482
1. Documents that only wish to be opened in cross-origin popups could loosen their cross-origin
428483
opener policy by serving the following headers:
429484

430-
<pre class="lang-http">
485+
<pre highlight="http">
431486
Cross-Origin-Resource-Policy: same-origin
432487
<strong>Cross-Origin-Opener-Policy: unsafe-none</strong>
433488
Vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site
@@ -442,7 +497,7 @@ or fetched cross-origin. Three scenarios are worth considering:
442497
2. Documents that only wish to be framed in cross-origin contexts could loosen their framing
443498
protections by serving the following headers:
444499

445-
<pre class="lang-http">
500+
<pre highlight="http">
446501
Cross-Origin-Resource-Policy: same-origin
447502
Cross-Origin-Opener-Policy: same-origin
448503
Vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site
@@ -457,11 +512,10 @@ or fetched cross-origin. Three scenarios are worth considering:
457512
addition to the `X-Frame-Options` header above, the following header could also be included to
458513
restrict the document to a short list of trusted embedders:
459514

460-
<pre class="lang-http">
515+
<pre highlight="http">
461516
Content-Security-Policy: frame-ancestors https://trusted1.example https://trusted2.example
462517
</pre>
463518
</div>
464-
465519

466520
For example:
467521

0 commit comments

Comments
 (0)