├── .gitignore ├── w3c.json ├── README.md ├── LICENSE.md ├── CODE_OF_CONDUCT.md ├── .github └── workflows │ └── build-validate-publish.yml ├── CONTRIBUTING.md ├── index.bs └── fpwd.html /.gitignore: -------------------------------------------------------------------------------- 1 | index.html 2 | -------------------------------------------------------------------------------- /w3c.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": [49309] 3 | , "contacts": ["wseltzer","weiler"] 4 | , "repo-type": "note" 5 | } 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Post-Spectre Web Development 2 | 3 | Sketching a threat model and concrete examples of mitigation. 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | All documents in this Repository are licensed by contributors 2 | under the 3 | [W3C Software and Document License](https://www.w3.org/Consortium/Legal/copyright-software). 4 | 5 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | All documentation, code and communication under this repository are covered by the [W3C Code of Ethics and Professional Conduct](https://www.w3.org/Consortium/cepc/). 4 | -------------------------------------------------------------------------------- /.github/workflows/build-validate-publish.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: {} 4 | push: 5 | branches: [main] 6 | 7 | jobs: 8 | main: 9 | name: Build, Validate, and Publish 10 | runs-on: ubuntu-20.04 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: w3c/spec-prod@v2 14 | with: 15 | GH_PAGES_BRANCH: gh-pages 16 | BUILD_FAIL_ON: nothing 17 | VALIDATE_LINKS: false 18 | VALIDATE_MARKUP: true 19 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Web Application Security Working Group 2 | 3 | Contributions to this repository are intended to become part of Recommendation-track documents governed by the 4 | [W3C Patent Policy](https://www.w3.org/Consortium/Patent-Policy-20040205/) and 5 | [Software and Document License](https://www.w3.org/Consortium/Legal/copyright-software). To make substantive contributions to specifications, you must either participate 6 | in the relevant W3C Working Group or make a non-member patent licensing commitment. 7 | 8 | If you are not the sole contributor to a contribution (pull request), please identify all 9 | contributors in the pull request comment. 10 | 11 | To add a contributor (other than yourself, that's automatic), mark them one per line as follows: 12 | 13 | ``` 14 | +@github_username 15 | ``` 16 | 17 | If you added a contributor by mistake, you can remove them in a comment with: 18 | 19 | ``` 20 | -@github_username 21 | ``` 22 | 23 | If you are making a pull request on behalf of someone else but you had no part in designing the 24 | feature, you can remove yourself with the above syntax. 25 | -------------------------------------------------------------------------------- /index.bs: -------------------------------------------------------------------------------- 1 |
  2 | Title: Post-Spectre Web Development
  3 | Shortname: post-spectre-webdev
  4 | Level: none
  5 | Status: ED
  6 | Group: WebAppSec
  7 | ED: https://w3c.github.io/webappsec-post-spectre-webdev/
  8 | TR: https://www.w3.org/TR/post-spectre-webdev/
  9 | Previous Version: from biblio
 10 | Editor: Mike West, Google, mkwst@google.com, w3cid 56384
 11 | Abstract:
 12 |     Post-Spectre, we need to adopt some new strategies for safe and secure web development. This
 13 |     document outlines a threat model we can share, and a set of mitigation recommendations.
 14 |     
 15 |     **TL;DR**: Your data must not unexpectedly enter an attacker's process.
 16 | Boilerplate: omit conformance
 17 | Markup Shorthands: css off, markdown on
 18 | 
19 |
 20 | urlPrefix: https://html.spec.whatwg.org/; spec: HTML;
 21 |     type: dfn
 22 |         text: origin; url: multipage/origin.html#concept-origin
 23 |         text: cross-origin opener policy; url: multipage/origin.html#cross-origin-opener-policies
 24 |         text: cross-origin embedder policy; url: multipage/origin.html#coep
 25 |     type: http-header
 26 |         text: cross-origin-opener-policy; url: multipage/origin.html#cross-origin-opener-policies
 27 |         text: x-frame-options; url: multipage/browsing-the-web.html#the-x-frame-options-header
 28 | urlPrefix: https://fetch.spec.whatwg.org/; spec: FETCH; type: dfn
 29 |     text: cross-origin resource policy; url: #http-cross-origin-resource-policy
 30 |     text: cross-origin read blocking; url: #corb
 31 | urlPrefix: https://tc39.es/ecma262/; spec: ECMA262; type: interface
 32 |     text: SharedArrayBuffer; url: #sec-sharedarraybuffer-objects
 33 | urlPrefix: https://tools.ietf.org/html/rfc7231; spec: RFC7231; type: http-header
 34 |     text: Vary; url: #section-7.1.4
 35 | urlPrefix: https://fetch.spec.whatwg.org/; spec: FETCH; type: http-header
 36 |     text: Origin; url: #origin-header
 37 | 
38 |
 39 | {
 40 |     "spectre": {
 41 |       "href": "https://ieeexplore.ieee.org/document/8835233",
 42 |       "title": "Spectre Attacks: Exploiting Speculative Execution",
 43 |       "publisher": "40th IEEE Symposium on Security and Privacy (S&P'19)",
 44 |       "date": "May 2019",
 45 |       "authors": [
 46 |         "Paul Kocher",
 47 |         "Jann Horn",
 48 |         "Anders Fogh",
 49 |         "Daniel Genkin",
 50 |         "Daniel Gruss",
 51 |         "Werner Haas",
 52 |         "Mike Hamburg",
 53 |         "Moritz Lipp",
 54 |         "Stefan Mangard",
 55 |         "Thomas Prescher",
 56 |         "Michael Schwarz",
 57 |         "Yuval Yarom"
 58 |       ]
 59 |     },
 60 |     "post-spectre-rethink": {
 61 |       "href": "https://chromium.googlesource.com/chromium/src/+/master/docs/security/side-channel-threat-model.md",
 62 |       "title": "Post-Spectre Threat Model Re-Think",
 63 |       "authors": [ "Chromium" ]
 64 |     },
 65 |     "site-isolation": {
 66 |       "href": "https://www.chromium.org/Home/chromium-security/site-isolation",
 67 |       "title": "Site Isolation",
 68 |       "authors": [ "Chromium" ]
 69 |     },
 70 |     "project-fission": {
 71 |       "href": "https://wiki.mozilla.org/Project_Fission",
 72 |       "title": "Project Fission",
 73 |       "authors": [ "Mozilla" ]
 74 |     },
 75 |     "resource-isolation-policy": {
 76 |       "href": "https://xsleaks.dev/docs/defenses/isolation-policies/resource-isolation/",
 77 |       "title": "Resource Isolation Policy",
 78 |       "authors": [ "XSLeaks Wiki" ]
 79 |     },
 80 |     "cross-origin-isolation-guide": {
 81 |       "href": "https://web.dev/cross-origin-isolation-guide/",
 82 |       "title": "A guide to enable cross-origin isolation",
 83 |       "authors": [ "Eiji Kitamura" ]
 84 |     },
 85 |     "coop-coep": {
 86 |       "href": "https://web.dev/coop-coep/",
 87 |       "title": "Making your website 'cross-origin isolated' using COOP and COEP",
 88 |       "authors": [ "Eiji Kitamura" ]
 89 |     },
 90 |     "coop-coep-explained": {
 91 |       "href": "https://docs.google.com/document/d/1zDlfvfTJ_9e8Jdc8ehuV4zMEu9ySMCiTGMS9y0GU92k/edit",
 92 |       "title": "COOP and COEP Explained",
 93 |       "authors": [ "Artur Janc", "Charlie Reis", "Anne van Kesteren" ],
 94 |       "date": "2020-01-03"
 95 |     },
 96 |     "application-principals": {
 97 |       "href": "https://noncombatant.org/application-principals/",
 98 |       "title": "Isolating Application-Defined Principals",
 99 |       "authors": [ "Chris Palmer" ],
100 |       "date": "2018-06-19"
101 |     },
102 |     "long-term-mitigations": {
103 |       "href": "https://docs.google.com/document/d/1dnUjxfGWnvhQEIyCZb0F2LmCZ9gio6ogu2rhMGqi6gY/edit",
104 |       "title": "Long-Term Web Browser Mitigations for Spectre",
105 |       "authors": [ "Charlie Reis" ],
106 |       "date": "2019-03-04"
107 |     },
108 |     "spectre-shaped-web": {
109 |       "href": "https://docs.google.com/presentation/d/1sadl7jTrBIECCanuqSrNndnDr82NGW1yyuXFT1Dc7SQ/edit#slide=id.p",
110 |       "title": "A Spectre-shaped Web",
111 |       "authors": [ "Anne van Kesteren" ],
112 |       "date": "2019-04-16"
113 |     },
114 |     "spilling-the-beans": {
115 |       "href": "https://www.arturjanc.com/cross-origin-infoleaks.pdf",
116 |       "title": "How do we Stop Spilling The Beans Across Origins?",
117 |       "authors": [ "Artur Janc", "Mike West" ],
118 |       "date": "2018-05-16"
119 |     },
120 |     "cross-origin-embedder-policy": {
121 |       "href": "https://wicg.github.io/cross-origin-embedder-policy/",
122 |       "title": "Cross-Origin Embedder Policy",
123 |       "authors": [ "Mike West" ],
124 |       "date": "2020-09-29"
125 |     },
126 |     "cross-origin-opener-policy-explainer": {
127 |       "href": "https://docs.google.com/document/d/1Ey3MXcLzwR1T7aarkpBXEwP7jKdd2NvQdgYvF8_8scI/edit",
128 |       "title": "Cross-Origin-Opener-Policy Explainer",
129 |       "authors": [ "Charlie Reis", "Camille Lamy" ],
130 |       "date": "2020-05-24"
131 |     },
132 |     "safely-reviving-shared-memory": {
133 |       "href": "https://hacks.mozilla.org/2020/07/safely-reviving-shared-memory/",
134 |       "title": "Safely reviving shared memory",
135 |       "authors": [ "Anne van Kesteren" ],
136 |       "date": "2020-07-21"
137 |     },
138 |     "coi-threat-model": {
139 |       "href": "https://arturjanc.com/coi-threat-model.pdf",
140 |       "title": "Notes on the threat model of cross-origin isolation",
141 |       "authors": [ "Artur Janc" ],
142 |       "date": "2020-12"
143 |     },
144 |     "orb": {
145 |       "href": "https://github.com/annevk/orb",
146 |       "title": "Opaque Response Blocking (ORB, aka CORB++)",
147 |       "authors": [ "Anne van Kesteren" ]
148 |     },
149 |     "oopif": {
150 |       "href": "https://www.chromium.org/developers/design-documents/oop-iframes",
151 |       "title": "Out-of-Process iframes (OOPIFs)",
152 |       "authors": [ "Chromium" ]
153 |     },
154 |     "embedding-requires-opt-in": {
155 |       "href": "https://github.com/mikewest/embedding-requires-opt-in",
156 |       "title": "Embedding Should Require Explicit Opt-In",
157 |       "authors": [ "Mike West" ]
158 |     },
159 |     "coop-by-default": {
160 |       "href": "https://github.com/mikewest/coop-by-default",
161 |       "title": "COOP By Default",
162 |       "authors": [ "Mike West" ]
163 |     }
164 | }
165 | 
166 | 167 | Introduction {#intro} 168 | ===================== 169 | 170 | In early 2018, Spectre made it clear that a foundational security boundary the web aimed to 171 | maintain was substantially less robust than expected. [[SPECTRE]] This revelation has pushed web 172 | browsers to shift their focus from the platform-level [=origin=] boundary to an OS-level 173 | process boundary. Chromium's threat model, for instance, now asserts that "active web content … 174 | will be able to read any and all data in the address space of the process that hosts it". 175 | [[POST-SPECTRE-RETHINK]] This shift in thinking imposes a shift in development practice, both 176 | for browser vendors, and for web developers. Browsers need to align the origin boundary with the 177 | process boundary through fundamental refactoring projects (for example, [[SITE-ISOLATION]] and 178 | [[PROJECT-FISSION]]). Moreover, browsers must provide web developers with tools to mitigate risk 179 | in the short term, and should push the platform towards safe default behaviors in the long term. 180 | The bad news is that this is going to be a lot of work, much of it falling on the shoulders of 181 | web developers. The good news is that a reasonable set of mitigation primitives exists today, 182 | ready and waiting for use. 183 | 184 | This document will summarize the threat model which the Web Application Security Working Group 185 | espouses, point to a set of mitigations which seem promising, and provide concrete recommendations 186 | for developers responsible for protecting users' data. 187 | 188 | Threat Model {#threat-model} 189 | ---------------------------- 190 | 191 | Spectre-like side-channel attacks inexorably lead to a model in which active web content 192 | (JavaScript, WASM, probably CSS if we tried hard enough, and so on) can read any and all data which 193 | has entered the address space of the process which hosts it. While this has deep implications for 194 | user agent implementations' internal hardening strategies (stack canaries, ASLR, etc), here we'll 195 | remain focused on the core implication at the web platform level, which is both simple and profound: 196 | any data which flows into a process hosting a given origin is legible to that origin. We must design 197 | accordingly. 198 | 199 | In order to determine the scope of data that can be assumed accessible to an attacker, we must make 200 | a few assumptions about the normally-not-web-exposed process model which the user agent implements. 201 | The following seems like a good place to start: 202 | 203 | 1. User agents are capable of separating the execution of a web origin's code into a process 204 | distinct from the agent's core. This separation enables the agent itself to access local 205 | devices, fetch resources, broker cross-process communication, and so on, in a way which remains 206 | invisible to any process potentially hosting untrusted code. 207 | 208 | 2. User agents are able to make decisions about whether or not a given resource should be delivered 209 | to a process hosting a given origin based on characteristics of both the request and the 210 | response (headers, etc). 211 | 212 | 3. User agents can consistently separate top-level, cross-origin windows into distinct processes. 213 | They cannot consistently separate same-site or same-origin windows into distinct processes given 214 | the potential for synchronous access between the windows. 215 | 216 | 4. User agents cannot yet consistently separate framed origins into processes distinct from their 217 | embedders' origin. 218 | 219 | Note: Though some user agents support out-of-process frames [[OOPIF]], no agent supports it 220 | consistently across a broad range of devices and platforms. Ideally this will change over time, 221 | as the frame boundary *must* be one we can eventually consider robust. 222 | 223 | With this in mind, our general assumption will be that an origin gains access to any resource which 224 | it renders (including images, stylesheets, scripts, frames, etc). Likewise, embedded frames gain 225 | access to their ancestors' content. 226 | 227 | ISSUE: [[COI-THREAT-MODEL]] spells out more implications. Bring them in here for more nuance. 228 | 229 | TL;DR {#tldr} 230 | ------------- 231 | 232 | 1. **Decide when (not!) to respond to requests** by examining incoming headers, paying special 233 | attention to the `Origin` header on the one hand, and various `Sec-Fetch-` 234 | prefixed headers on the other, as described in [[resource-isolation-policy]]. 235 | 236 | 2. **Restrict attackers' ability to load your data as a subresource** by setting a 237 | [=cross-origin resource policy=] (CORP) of `same-origin` (opening up to `same-site` 238 | or `cross-origin` only when necessary). 239 | 240 | 3. **Restrict attackers' ability to frame your data as a document** by opt-ing into framing 241 | protections via `X-Frame-Options: SAMEORIGIN` or CSP's more granular [=frame-ancestors=] 242 | directive (`frame-ancestors 'self' https://trusted.embedder`, for example). 243 | 244 | 4. **Restrict attackers' ability to obtain a handle to your window** by setting a 245 | [=cross-origin opener policy=] (COOP). In the best case, you can default to a restrictive 246 | `same-origin` value, opening up to `same-origin-allow-popups` or `unsafe-none` only if 247 | necessary. 248 | 249 | 5. **Prevent MIME-type confusion attacks** and increase the robustness of passive defenses like 250 | [=cross-origin read blocking=] (CORB) / 251 | opaque response blocking ([[ORB]]) by setting 252 | correct `Content-Type` headers, and globally asserting `X-Content-Type-Options: nosniff`. 253 | 254 | ISSUE: Describe these mitigations in more depth, swiping liberally from 255 | Notes on the threat model of *cross-origin isolation*, 256 | Safely reviving shared memory, etc. 257 | 258 | Practical Examples {#examples} 259 | ============================== 260 | 261 | Subresources {#subresources} 262 | ---------------------------- 263 | 264 | Resources which are intended to be loaded into documents should protect themselves from being used 265 | in unexpected ways. Before walking through strategies for specific kinds of resources, a few headers 266 | seem generally applicable: 267 | 268 | 1. Sites should use Fetch Metadata to make good decisions about when to serve resources, as 269 | described in [[resource-isolation-policy]]. In order to ensure that decision sticks, servers 270 | should explain its decision to the browser by sending a `Vary` header 271 | containing `Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site, Sec-Fetch-User`. This ensures that 272 | the server has a chance to make different decisions for requests which will be *used* 273 | differently. 274 | 275 | 2. Subresources should opt-out of MIME type sniffing by sending an 276 | `X-Content-Type-Options` header with a value of `nosniff`. This increases the 277 | robustness of MIME-based checks like [=cross-origin read blocking=] (CORB) / 278 | opaque response blocking ([[ORB]]), and mitigates 279 | some well-known risks around type confusion for scripts. 280 | 281 | 3. Subresources are intended for inclusion in a given context, not as independently navigable 282 | documents. To mitigate the risk that navigation to a subresource causes script execution or 283 | opens an origin up to attack in some other way, servers can assert the following set of headers 284 | which collectively make it difficult to meaningfully abuse a subresource via navigation: 285 | 286 | * Using the `Content-Security-Policy` header's to assert the 287 | `sandbox` directive ensures that these resources remain inactive if navigated to 288 | directly as a top-level document. No scripts will execute, and the resource will be pushed 289 | into an [=opaque origin=]. 290 | 291 | Note: Some servers deliver `Content-Disposition: attachment; filename=file.name` to obtain 292 | a similar effect. This was valuable to mitigate vulnerabilities in Flash, but the sandbox 293 | approach seems to more straightforwardly address the threats we care about today. 294 | 295 | * Asserting the `Cross-Origin-Opener-Policy` header with a value of 296 | `same-origin` prevents cross-origin documents from retaining a handle to the resource's 297 | window if it's opened in a popup. 298 | 299 | * The `X-Frame-Options` header with a value of `DENY` prevents the resource 300 | from being framed. 301 | 302 | Most subresources, then, should contain the following block of headers, which you'll see repeated a 303 | few times below: 304 | 305 |
306 | Content-Security-Policy: sandbox
307 | Cross-Origin-Opener-Policy: same-origin
308 | Vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site, Sec-Fetch-User
309 | X-Content-Type-Options: nosniff
310 | X-Frame-Options: DENY
311 | 
312 | 313 | With these generic protections in mind, let's sift through a few scenarios to determine what headers 314 | a server would be well-served to assert: 315 | 316 | ### Static Subresources ### {#static-subresources} 317 | 318 | By their nature, static resources contain the same data no matter who requests them, and therefore 319 | cannot contain interesting information that an attacker couldn't otherwise obtain. There's no risk 320 | to making these resources widely available, and value in allowing embedders to robustly debug, so 321 | something like the following response headers could be appropriate: 322 | 323 |
324 | Access-Control-Allow-Origin: *
325 | Cross-Origin-Resource-Policy: cross-origin
326 | Timing-Allow-Origin: *
327 | Content-Security-Policy: sandbox
328 | Cross-Origin-Opener-Policy: same-origin
329 | X-Content-Type-Options: nosniff
330 | X-Frame-Options: DENY
331 | 
332 | 333 | Note: Purely static resources always respond with the same data, no matter the request. There's 334 | therefore little benefit to sending a `Vary` header: it can be safely omitted for these responses. 335 | 336 | CDNs are the canonical static resource distribution points, and many use the pattern above. Take 337 | a look at the following common resources' response headers for inspiration: 338 | 339 | * `https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js` 340 | * `https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js` 341 | * `https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js` 342 | * `https://ssl.google-analytics.com/ga.js` 343 | 344 | Similarly, application-specific static resource servers are a good place to look for this practice. Consider: 345 | 346 | * `https://static.xx.fbcdn.net/rsrc.php/v3/y2/r/zVvRrO8pOtu.png` 347 | * `https://www.gstatic.com/images/branding/googlelogo/svg/googlelogo_clr_74x24px.svg` 348 | 349 | ### Dynamic Subresources ### {#dynamic-subresources} 350 | 351 | Subresources that contain data personalized to a given user are juicy targets for attackers, and 352 | must be defended by ensuring that they're loaded only in ways that are appropriate for the data 353 | in question. A few cases are well worth considering: 354 | 355 | 1. Application-internal resources (private API endpoints, avatar images, uploaded data, etc.) 356 | should not be available to any cross-origin requestor. These resources should be restricted to 357 | usage as a subresource in same-origin contexts by sending a 358 | `Cross-Origin-Resource-Policy` header with a value of `same-origin`: 359 | 360 |
361 | 	  Cross-Origin-Resource-Policy: same-origin
362 |     Content-Security-Policy: sandbox
363 |     Cross-Origin-Opener-Policy: same-origin
364 |     Vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site, Sec-Fetch-User
365 |     X-Content-Type-Options: nosniff
366 |     X-Frame-Options: DENY
367 |     
368 | 369 | This header will prevent cross-origin attackers from loading the resource as a response to a 370 | `no-cors` request. 371 | 372 | For example, examine the headers returned when requesting endpoints like the following: 373 | 374 | * `https://myaccount.google.com/_/AccountSettingsUi/browserinfo` 375 | * `https://twitter.com/i/api/1.1/branch/init.json` 376 | * `https://www.facebook.com/ajax/webstorage/process_keys/?state=0` 377 | 378 | 2. Personalized resources intended for cross-origin use (public API endpoints, etc) should 379 | carefully consider incoming requests' properties before responding. These endpoints can only 380 | safely be enabled by requiring CORS, and choosing the set of origins for which a given response 381 | can be exposed by setting the appropriate access-control headers, for example: 382 | 383 |
384 |     Access-Control-Allow-Credentials: true
385 |     Access-Control-Allow-Origin: https://trusted.example
386 |     Access-Control-Allow-Methods: POST
387 |     Access-Control-Allow-Headers: ...
388 |     Access-Control-Allow-...: ...
389 |     Cross-Origin-Resource-Policy: same-origin
390 |     Content-Security-Policy: sandbox
391 |     Cross-Origin-Opener-Policy: same-origin
392 |     Vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site, Sec-Fetch-User
393 |     X-Content-Type-Options: nosniff
394 |     X-Frame-Options: DENY
395 |     
396 | 397 | Note: The `Cross-Origin-Resource-Policy` header is only processed for requests that are _not_ 398 | using CORS for access control ("`no-cors` requests"). Sending 399 | `Cross-Origin-Resource-Policy: same-origin` is therefore not harmful, and works to ensure that 400 | `no-cors` usage isn't accidentally allowed. 401 | 402 | For example, examine the headers returned when requesting endpoints like the following: 403 | 404 | * `https://api.twitter.com/1.1/jot/client_event.json` 405 | * `https://play.google.com/log?format=json&hasfast=true` 406 | * `https://securepubads.g.doubleclick.net/pcs/view` 407 | * `https://c.amazon-adsystem.com/e/dtb/bid` 408 | 409 | 3. Personalized resources that are intended for cross-origin `no-cors` embedding, but which don't 410 | intend to be directly legible in that context (avatar images, authenticated media, etc). These 411 | should enable cross-origin embedding via `Cross-Origin-Resource-Policy`, but _not_ via CORS 412 | access control headers: 413 | 414 |
415 |     Cross-Origin-Resource-Policy: cross-origin
416 |     Content-Security-Policy: sandbox
417 |     Cross-Origin-Opener-Policy: same-origin
418 |     Vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site, Sec-Fetch-User
419 |     X-Content-Type-Options: nosniff
420 |     X-Frame-Options: DENY
421 |     
422 | 423 |
424 | Note: That this allows the resource to be used by any cross-origin document. That's 425 | reasonable for some use cases, but requiring CORS, and opting-in a small set of origins via 426 | appropriate access-control headers is a possible alternative for some resources. This 427 | approach will give those contexts trivial access to the resource's bits, so the granularity 428 | is a tradeoff. Still, considering this case to be the same as the "personalized resources 429 | intended for cross-origin use" isn't unreasonable. 430 | 431 | ISSUE(whatwg/fetch#760): If we implemented more granular bindings for CORP headers (along 432 | the lines of `Cross-Origin-Resource-Policy: https://trusted.example`), we could avoid this 433 | tradeoff entirely. 434 |
435 | 436 | 437 | For example: 438 | 439 | * `https://lh3.google.com/u/0/d/1JBUaX1xSOZRxBk5bRNZWgnzyJoCQC52TIRokACBSmGc=w512` 440 | 441 | 442 | Documents {#documents} 443 | ---------------------- 444 | 445 | ### Fully-Isolated Documents ### {#documents-isolated} 446 | 447 | Documents that require users to be signed-in almost certainly contain information that shouldn't be 448 | revealed to attackers. These pages should take care to isolate themselves from other origins, both 449 | by making _a priori_ decisions about whether to serve the page at all (see 450 | [[resource-isolation-policy]], for example), and by giving clients careful instructions about how 451 | the page can be used once delivered. For instance, something like the following set of response 452 | headers could be appropriate: 453 | 454 |
455 | Cross-Origin-Opener-Policy: same-origin
456 | Cross-Origin-Resource-Policy: same-origin
457 | Vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site, Sec-Fetch-User
458 | X-Content-Type-Options: nosniff
459 | X-Frame-Options: SAMEORIGIN
460 | 
461 | 462 | Note: Documents which need to make use of APIs that require full cross-origin isolation (such 463 | as {{SharedArrayBuffer}}), will also need to serve a `Cross-Origin-Embedder-Policy` header, as 464 | outlined in [[coop-coep]] and [[cross-origin-isolation-guide]]. 465 | 466 | Account settings pages, admin panels, and application-specific documents are all good examples of 467 | resources which would benefit from as much isolation as possible. For real-life examples, consider: 468 | 469 | * `https://myaccount.google.com/` 470 | 471 | 472 | ### Documents Expecting to Open Cross-Origin Windows ### {#documents-with-popups} 473 | 474 | Not every document that requires sign-in can be fully-isolated from the rest of the internet. It's 475 | often the case that partial isolation is a better fit. Consider sites that depend upon cross-origin 476 | windows for federated workflows involving payments or sign-in, for example. These pages would 477 | generally benefit from restricting attackers' ability to embed them, or obtain their window handle, 478 | but they can't easily lock themselves off from all such vectors via 479 | `Cross-Origin-Opener-Policy: same-origin` and `X-Frame-Options: DENY`. In these cases, something 480 | like the following set of response headers might be appropriate: 481 | 482 |
483 | Cross-Origin-Opener-Policy: same-origin-allow-popups
484 | Cross-Origin-Resource-Policy: same-origin
485 | Vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site, Sec-Fetch-User
486 | X-Content-Type-Options: nosniff
487 | X-Frame-Options: SAMEORIGIN
488 | 
489 | 490 | The only difference between this case and the "Fully-Isolated" case above is the 491 | `Cross-Origin-Opener-Policy` value. `same-origin` will break the opener relationship between the 492 | document and any cross-origin window, regardless of who opened whom. 493 | `same-origin-allow-popups` will break cross-origin opener relationships initiated by a cross-origin 494 | document's use of `window.open()`, but will allow the asserting document to open cross-origin 495 | windows that retain an opener relationship. 496 | 497 | 498 | ### Documents Expecting Cross-Origin Openers ### {#documents-as-popups} 499 | 500 | Federated sign-in forms and payment providers are clear examples of documents which intend to be 501 | opened by cross-origin windows, and require that relationship to be maintained in order to 502 | facilitate communication via channels like {{Window/postMessage(message, options)}} or navigation. 503 | These documents cannot isolate themselves completely, but can prevent themselves from being embedded 504 | or fetched cross-origin. Three scenarios are worth considering: 505 | 506 | 1. Documents that only wish to be opened in cross-origin popups could loosen their cross-origin 507 | opener policy by serving the following headers: 508 | 509 |
510 |     Cross-Origin-Resource-Policy: same-origin
511 |     Cross-Origin-Opener-Policy: unsafe-none
512 |     Vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site, Sec-Fetch-User
513 |     X-Content-Type-Options: nosniff
514 |     X-Frame-Options: SAMEORIGIN
515 |     
516 | 517 | For example: 518 | 519 | * ISSUE: Find some links. 520 | 521 | 2. Documents that only wish to be framed in cross-origin contexts could loosen their framing 522 | protections by serving the following headers: 523 | 524 |
525 |     Cross-Origin-Resource-Policy: same-origin
526 |     Cross-Origin-Opener-Policy: same-origin
527 |     Vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site, Sec-Fetch-User
528 |     X-Content-Type-Options: nosniff
529 |     X-Frame-Options: ALLOWALL
530 |     
531 | 532 |
533 | Note: That this allows embedding by any cross-origin documents. That's reasonable for some 534 | widgety use cases, but when possible, a more secure alternative would specify a list of origins 535 | which are allowed to embed the document via the [=frame-ancestors=] CSP directive. That is, in 536 | addition to the `X-Frame-Options` header above, the following header could also be included to 537 | restrict the document to a short list of trusted embedders: 538 | 539 |
540 |         Content-Security-Policy: frame-ancestors https://trusted1.example https://trusted2.example
541 |         
542 |
543 | 544 | For example: 545 | 546 | * ISSUE: Find some links. 547 | 548 | 3. Documents that support both popup and framing scenarios need to loosen both their cross-origin 549 | opener policies and framing protections by combining the recommendations above, serving the 550 | following headers: 551 | 552 |
553 |     Cross-Origin-Resource-Policy: same-origin
554 |     Cross-Origin-Opener-Policy: unsafe-none
555 |     Vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site, Sec-Fetch-User
556 |     X-Content-Type-Options: nosniff
557 |     X-Frame-Options: ALLOWALL
558 |     
559 | 560 | For example: 561 | 562 | * ISSUE: Find some links. 563 | 564 | Implementation Considerations {#considerations} 565 | =============================================== 566 | 567 | Explicitly Setting Headers with Default Values {#explicit-defaults} 568 | ------------------------------------------------------------------- 569 | 570 | Several recommendations above suggest that developers would be well-served to set headers like 571 | `X-Frame-Options: ALLOWALL` or `Cross-Origin-Opener-Policy: unsafe-none` on responses. These 572 | map to the web's status quo behavior, and seem therefore superfluous. Why should developers 573 | set them? 574 | 575 | The core reason is that these defaults are poor fits for today's threats, and we ought to be working 576 | to change them. Proposals like [[EMBEDDING-REQUIRES-OPT-IN]] and [[COOP-BY-DEFAULT]] suggest that 577 | we shift the web's defaults away from requiring developers to opt-into more secure behaviors by 578 | making them opt-out rather than opt-in. This would place the configuration cost on those developers 579 | whose projects require risky settings. 580 | 581 | This document recommends setting those less-secure header values explicitly, as that makes it more 582 | likely that we'll be able to shift the web's defaults in the future. 583 | 584 | Isolating Local-Scheme Frames {#local-scheme-frames} 585 | ---------------------------------------------------- 586 | 587 | Note that frames loaded from local schemes will generally inherit policies applied to the document 588 | which created them, and may end up in-process with that document if the stars align unfortunately. 589 | Developers are encouraged to explicitly shift these documents to opaque origins, either by using 590 | `data:` URLs directly, or by applying a <{iframe/sandbox}> attribute to frames created using 591 | `