Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

is mandating CORS for modules the right tradeoff? #1888

Closed
dherman opened this issue Oct 11, 2016 · 72 comments
Closed

is mandating CORS for modules the right tradeoff? #1888

dherman opened this issue Oct 11, 2016 · 72 comments

Comments

@dherman
Copy link

dherman commented Oct 11, 2016

For the Mozilla implementation of <script type=module>, I have some concerns about the mandatory CORS requirement before we're ready to ship an implementation. I was hoping we could have a discussion here to see if we could get some clarity around the tradeoffs of this particular question.

As I see it, the risk of imposing a stricter CORS requirement for module scripts than for classic scripts is an adoption tax: it adds an extra burden for hosts serving modules to multiple origins. The obvious category is CDNs that aren't currently serving CORS headers, but there are also use cases like single-vendor apps with asset subdomains, and perhaps others we aren't thinking of.

While I'm sure some might think of that as a feature -- i.e., using modules to incentivize the adoption of CORS -- we have to contend with the multiplied adoption risks, and it's hard for me to really know how to evaluate that risk. (It'd be helpful to hear from multi-origin authors and hosts, BTW, to hear whether they think this kind of change is something they feel they can absorb, or whether mandatory CORS would cause them any roadblocks.)

Meanwhile, it's not clear to me what the precise rationale is. My assumption is that there's a security argument, but I'd like some clarity about what it is.

The first question is, is this attempting to migrate the web away from existing security issues, or is it attempting to prevent some new security issue? The former seems implausible to me; no matter how widespread the adoption of module scripts, you can't prevent malicious content from using classic scripts. IOW, closing any historical <script> gaps in the design of <script type=module> doesn't stop attackers from using <script>.

If the claim is that modules introduce some new issue, we should try to be clear about what that is. So far I haven't been able to puzzle out a threat model for which module scripts are meaningfully different from classic scripts:

  • Malicious server side effects? Even with mandated CORS, the spec doesn't use preflighting, so even as written it doesn't prevent module scripts from triggering any of the same side effects that classic scripts can.
  • Leaking sensitive information from the server to the client by reading fetched data? Non-CORS data is censored in the browser.
  • Leaking sensitive information from the server to the client via script execution? Classic scripts have all the same execution powers as module scripts; modules add import but of course classic scripts can already XHR/fetch.
  • Leaking sensitive server files in data formats (CSV, JSON, etc) by treating them as JS? The import/export syntax is the only difference from the JS grammar, and doesn't plausibly overlap with any data file formats.
  • What else? I had a brief chat with @annevk, who mentioned something about leaking cross-origin referer information in transitive loads, but I don't understand the threat model (nor how it differs from, for example, cross-origin CSS with imports).

The primary benefit of requiring no-preflight CORS seems to be the additional power to read cross-origin data (script source, stack traces). But that's not enough to justify the removal of the power to execute cross-origin module scripts without CORS.

If there is a threat model that no-preflight CORS is supposed to protect against with module scripts, I'd like to understand what it is. Even just an example exploit would be helpful. If we can understand the rationale, we can evaluate the tradeoffs.

cc: @domenic, @annevk, @jonco3

@domenic
Copy link
Member

domenic commented Oct 11, 2016

The web's fundamental security model is the same origin policy. We have several legacy exceptions to that rule from before that security model was in place, with script tags being one of the most egregious and most dangerous. (See the various "JSONP" attacks.)

Many years ago, perhaps with the introduction of XHR or web fonts (I can't recall precisely), we drew a line in the sand, and said no new web platform features would break the same origin policy. The existing features need to be grandfathered in and subject to carefully-honed and oft-exploited exceptions, for the sake of not breaking the web, but we certainly can't add any more holes to our security policy.

That's why, from our perspective, making module scripts bypass the CORS protocol (and thus the same-origin policy) is a non-starter. It's not about a specific attack scenario, apart from the ones already enabled by classic scripts; it's about making sure that new features added to the platform don't also suffer from the past's bad security hygiene.

@bmaurer
Copy link

bmaurer commented Oct 11, 2016

At Facebook we started using CORS long ago due to the advantages of getting stack traces. I agree with the principle here that script tags are basically just a non-declared CORS. I would add two insights:

  • This seems like one of the first cases where somebody would have to add CORS headers to files on disk (vs something that would be served as dynamic content). Put another way -- traditionally one could create a website just by having a web server like apache serve a directory of files using the default settings. This is handy in many ways -- for example, internally at fb we serve your ~/public_html directory on an internal webserver. There's no ability for you to specify a server configuration of any sort. This seems like it could trip people up (though I guess in this case maybe you get by since everything is same origin)
  • Using crossorigin=anonymous has a distinct disadvantage that it forces many browsers (at least chrome) to prevent sharing of the socket with non-anonymous resources. We found that by using crossorigin=anonymous we had inadvertently been preventing HTTP2 reuse. We should probably increase awareness of the impact of using anonymous on connection reuse

@domenic
Copy link
Member

domenic commented Oct 11, 2016

This seems like one of the first cases where somebody would have to add CORS headers to files on disk

Hmm, I don't understand this point very well. Web fonts require CORS. In many canvas-based scenarios (canvas being introduced around the same time as the line in the sand I mentioned earlier), images require CORS. Any static data files (e.g. .json) requested via fetch/XHR require CORS. HTML imports (RIP) required CORS. Etc.

internally at fb we serve your ~/public_html directory on an internal webserver. There's no ability for you to specify a server configuration of any sort. This seems like it could trip people up (though I guess in this case maybe you get by since everything is same origin)

Yeah, this is actually a perfect illustration of the issue. We want the SOP to protect you from reading and executing scripts from other peoples' public_html directories, but within your own, there's no issue at all.

Using crossorigin=anonymous has a distinct disadvantage that it forces many browsers (at least chrome) to prevent sharing of the socket with non-anonymous resources.

This is interesting, but seems fairly orthogonal to the current discussion. FWIW, the spec defaults to credentials mode "omit" (same as Fetch), with the option of using crossorigin=anonymous to get "same-origin", or crossorigin=use-credentials to get "include". If this is potentially problematic, it might be worth opening a separate issue.

@hillbrad
Copy link

The CORS requirement is also beneficial from an ecosystem perspective in that explicitly marking public content and requiring anonymous loads allows improvements in security and performance (like Subresource Integrity and content-addressable caching) that privacy concerns forbid without such explicit signals.

@dherman
Copy link
Author

dherman commented Oct 11, 2016

@domenic:

Many years ago, perhaps with the introduction of XHR or web fonts (I can't recall precisely), we drew a line in the sand, and said no new web platform features would break the same origin policy.

What constitutes "new web platform features" here? Did <script async> get standardized before or after this pledge? These aren't petty questions, they're exactly relevant: there are key empirical differences between a brand new capability like fonts versus an improved delta on an existing capability like module scripts.

These differences affect both the security calculus (can we actually close loopholes without changing/removing existing features?) and the adoption calculus (will people move from what they can currently do if the new thing reduces functionality?).

It's not about a specific attack scenario, apart from the ones already enabled by classic scripts; it's about making sure that new features added to the platform don't also suffer from the past's bad security hygiene.

OK, that's a start: IOW, your answer to my first question is that this is about closing existing loopholes.

But as I said, this doesn't actually close them since <script> still exists. Take your JSONP example. I think you're basically trying to use modules as a carrot to eliminate it from practical usage. I'm no JSONP apologist, but if we eliminate it from module scripts, people can keep on using classic scripts. We haven't actually prevented the practice. And now there are confusing rules about when to use classic scripts and when to use module scripts—and the easier thing to learn is "don't use module scripts."

Put differently: with security considerations, we generally try to avoid the devil we don't know. But in this case, because of the existence of classic scripts, the security issues are the devil we know. It's the adoption risks that are the devil we don't know. In fact, I doubt this would be up for debate with <script async>, so why is <script type=module> different? The answer isn't that we made a pledge years ago; it has to be a specific argument about whether and why there will be practical improvements to security in practice even though the existing features continue to exist, and whether the loss of functionality in the new thing will be tolerable.

@domenic
Copy link
Member

domenic commented Oct 11, 2016

Did <script async> get standardized before or after this pledge?

The async attribute has been present in some form (buggy or not) for many years; the spec was largely codifying what existed at the time.

But as I said, this doesn't actually close them since <script> still exists.

Yes, as I stated, this is not about preventing existing attacks. It's about making sure that new features added to the platform don't also suffer from the past's bad security hygiene.

In fact, I doubt this would be up for debate with <script async>

Precisely: if we were specifying script async today, it would fall clearly on the side of the line I mentioned, and we would require CORS for it.

@dherman
Copy link
Author

dherman commented Oct 11, 2016

Precisely: if we were specifying script async today, it would fall clearly on the side of the line I mentioned, and we would require CORS for it.

Really? I find this very surprising.

@domenic
Copy link
Member

domenic commented Oct 11, 2016

Yep, really!

Also, I forgot:

But in this case, because of the existence of classic scripts, the security issues are the devil we know.

That's not really correct. New attacks are discovered on classic scripts all the time. Remember when people thought JSONP was safe, instead of its modern reputation as a huge XSS bug farm? Remember the great cross-origin Proxy debacle of 2015, which required changes in HTML/Web IDL/ES to address by locking down the prototype chain of all the global objects? (And even that only protected against the gaping hole of proxies; it doesn't protect against targeted attacks using getters, to which the web is still vulnerable.) The fact is that breaking the SOP breaks the fundamental protection we have on the web, and we're constantly scrambling to put the genie back in the bottle given classic scripts' failure to obey it. That's why we're not going to be breaking it for any future features going forward.

@dherman
Copy link
Author

dherman commented Oct 11, 2016

Yep, really!

Well, obviously I disagree. :) All I can say is, I don't find the line of reasoning of "there's a pre-existing pledge" as compelling rationale for anything.

New attacks are discovered on classic scripts all the time. … That's why we're not going to be breaking it for any future features going forward.

You're not actually addressing my point, though. We can't actually close the loopholes without breaking web compat, because we can't break the web—as we all agree. So the loopholes exist, and now we're talking about standardizing a variation of the same feature. All I'm asking is that we engage with the practical adoption consequences, where the security consequences are already being dealt with and can't ever be eliminated.

We can stand on a predetermined black-and-white principle and ignore the empirical consequences, but… reality bites! :)

@wanderview
Copy link
Member

@dherman How is this any different than restricting things like brotli to https when gzip can be used on http? Clearly the better compression would get adopted faster if it was on http, but we don't want to take the risk vector.

@ekr
Copy link

ekr commented Oct 11, 2016

@dherman How is this any different than restricting things like brotli to https when gzip
can be used on http? Clearly the better compression would get adopted faster if it was
on http, but we don't want to take the risk vector.

Without taking a position on the bigger issue, this seems like kind of an odd example given the known security issues with combining compression with HTTPS.

Incidentally, what's the risk vector that you are concerned about with exposing Brotli to HTTP?

@dherman
Copy link
Author

dherman commented Oct 11, 2016

@wanderview I don't know as much about compression and network protocols, nor do I have an opinion about whether that was the right call. But off the top of my head I imagine it's possible to enable brotli compression automatically in server software, without developers needing to change anything about how they develop their code. What we're talking about here is mixing two different programming models, where the new one doesn't supersede the old one. Often when new programming models are introduced that bring a new benefit but eliminate an old one, it can cause years of stagnated adoption, or even fail outright.

@kg
Copy link

kg commented Oct 11, 2016

As a web application and tooling developer (i.e. JSIL) I find this constraint extremely troubling, though the motivations behind it are good.

The HTTPS requirements for new tech being applied by many browser vendors already impose some hurdles for amateur web developers and people maintaining old stacks, but at the very least this has dramatic upsides for users, so it's very easy to get behind it and direct force towards addressing ecosystem challenges that prevent every web service and server from supporting HTTPS.

I think the same is not true for CORS. CORS is nontrivial to configure, nontrivial to interact with, and most importantly, extremely inconvenient to test locally in development scenarios. Many people still locally host their applications using things like python's httpd module for testing, especially since file:// is crippled in Popular Browsers. A CORS requirement for modules potentially requires amateurs to set up a whole server environment and figure out CORS just to test simple module-based applications. In the past I've worked with development environments at larger companies (30m+ users) that would also incur a significant burden if we had attempted to adopt a technology like this and introduce CORS everywhere.

The web has moved forward so I'm sure it's easier now, but in the past when I attempted to use CORS (because I had to in order for my relatively simple application to work cross-browser) it was a struggle to find even one CDN with support, and it was difficult to get the configuration right so it would actually work. Testing CORS in local debugging scenarios was basically impossible.

It's also not clear how users in shared-hosting scenarios would (as @bmaurer points out) actually configure CORS in their use cases - it would require some sort of local configuration file (.htaccess etc) in order to provide appropriate CORS headers for each resource. It's possible some web servers are not capable of doing this so now we would actually need new server logic to go through development, testing, and package manager updates.

As much as I view modules as a sorely-needed ECMAScript improvement that addresses some things I've always disliked, this requirement seems likely to Python 3 them as a production feature if the ecosystem isn't ready yet. I think a lot of testing and research is required to ensure that the ecosystem is ready, and probably some aggressive tech evangelism to move things along.

Things like brotli and brand new web platform features are more incremental, optional improvements so it is more reasonable to gate them behind things like HTTPS. Modules are such a fundamental quality-of-life improvement - one that we really want everyone to move to as quickly as possible - that gating them seems ill-advised.

@domenic
Copy link
Member

domenic commented Oct 11, 2016

@kg, I don't see why this would require any server configuring for your use cases. Note that CORS headers are only required by sites which wish to expose their modules to third parties, not for your own modules or for local servers or anything like that.

@kg
Copy link

kg commented Oct 11, 2016

If I'm testing multiple-domain scenarios locally I'm going to need CORS headers, aren't I?

@domenic
Copy link
Member

domenic commented Oct 11, 2016

Yes, but that's already true for all existing resources (images in canvas, fetch, web fonts, XHR, etc) that aren't grandfathered in under the legacy tech loophole.

@yoavweiss
Copy link
Contributor

yoavweiss commented Oct 12, 2016

@dherman How is this any different than restricting things like brotli to https when gzip can be used on http? Clearly the better compression would get adopted faster if it was on http, but we don't want to take the risk vector.

@wanderview - Limiting brotli to HTTPS was (at least partially) based on the fact that deploying it over HTTP would mean existing intermediaries will break it in passing. Not really security related AFAIK.

@wanderview
Copy link
Member

Ok, sorry for my confusion. It seemed similar to me, but clearly I'm out of my depth. :-)

@domenic
Copy link
Member

domenic commented Jan 12, 2017

Let's close this. All the arguments have been made and given their fair shake, and in the end the one reason given for relaxing the security properties of the same-origin policy ("adoption hazard" compared with classic scripts) does not suffice to convince the editors.

Furthermore, there is the question of implementations. For Chrome's part, we are unwilling to ship modules if doing so introduces another cross-origin security hole. And the prototype implementations in WebKit and Edge conform to the security guarantees in the current spec. That puts us at 3/4 in favor of the current spec.

We can perhaps revisit this question with more data later. If it turns out that, after some years in the wild, module adoption is suffering because people are unable to add CORS headers to modules they want to use cross-origin, we can consider relaxing the constraint here, with appropriate security ameliorations (e.g. blocking stack traces and perhaps function.toString). But we cannot regain security after we have given it away. And note that at least one potential large adopter of modules, Facebook, has stated the opposite in preference (toward the current spec) in #1888 (comment).

Thanks everyone for the discussion. In the end, after all arguments have been laid out, we need to make a decision, and given the conflicting priorities here of security vs. adoption, I realize not everyone is going to be happy. I hope you can understand why we've made the choice we did.

@domenic domenic closed this as completed Jan 12, 2017
@BrendanEich
Copy link

BrendanEich commented Jan 14, 2017

Same-origin was buggy and underspecified (and still is), but this is just revisionism:

"The web's fundamental security model is the same origin policy. We have several legacy exceptions to that rule from before that security model was in place, with script tags being one of the most egregious and most dangerous."

I implemented primitive SOP at Netscape starting in Netscape 2 in 1995. Origins could interact via frames and windows even before <script src=> (e.g., window.open -- lots of bugs in early days). <script src=> did not show up till 1996, in Netscape 3, which had slightly less buggy SOP and an optional alternative (the data tainting model). That we have had bugs to fix up to and including 2015's proxy-as-global-prototype is not a recommendation for mandating CORS for modules, since we'll have to keep supporting non-module scripts, and fixing the never-perfect-now-or-in-the-past SOP, anyway.

From this issue I conclude script src=module will not be adopted as well as it would otherwise, and we'll have 3rd party scripts approximately forever.

@annevk
Copy link
Member

annevk commented Jan 15, 2017

A new attack surface is that module scripts parse differently which could lead to details of module scripts (or things that look like them) being observed by an attacker (e.g., through a service worker).

So we then have the option of enshrining this new leak, designing workarounds (e.g., bypassing service workers unless CORS is used), or starting with the safe thing. The safe thing is most conservative and would still allow us for lifting that in some way going forward, just like you can typically move from throwing an exception to not doing that.

@BrendanEich
Copy link

BrendanEich commented Jan 15, 2017

@annevk Could you give an example? Yes, modules parse differently. No, this doesn't create any more "attack surface" than today. Modules do not pollute the global scope, so there's less surface to first order. Side channels are all around us and don't weigh one way or the other.

Imagine we try to get rid of non-module scripts. We add some CSP directive by which authors can require CORS for script src=. Same would apply to script type=module src=. In the mean time, the use of modules grew better without this CORS security theater, which is a real tax on adoption.

To believe security would be worse without CORS, you have to believe it's worse now for all the third party scripts out there, and that we can lead people to adopt both modules and CORS for their future third-party code sharing.

Don't get me started on third-party script security (I founded Brave to block the parasitic third party by default). Security is bad enough, we know, but compare apples to apples. The comparison is not between better security by using modules as carrot for the CORS stick. It's rather between today's no-module world and one that we can evolve to that might have more modules and more CORS.

It's rare in my experience to see effort in ad-tech to switch to CORS for third party scripts (video is where you see CORS more, via SDKs, due to VAST; it's very rare in display). Don't ask Facebook, they are a giant intranet. Ask Google's publisher and ad partners. Let's see CORS mandated and then talk.

So I still say all y'all are doing is entrenching script src= without modules. Hypotheticals about security do not count.

But do give a concrete attack that non-CORS type=module introduces, if you can. Be explicit, no hand-waves that apply to non-module scripts as much or more. SWs can see all requests, so the "leak" would apply in either the type=module or old-style script src= case. Nested imports or generated script tags or XHRed code loads or whatever, doesn't matter -- SWs see all.

@annevk
Copy link
Member

annevk commented Jan 15, 2017

E.g., a resource (from which the attacker knows/guesses the URL somehow, but cannot get at the contents (cookies, firewall)) import * as filters from "secret-key" would leak "secret-key" with <script type=module>, but not with <script>.

@BrendanEich
Copy link

@annevk: you wrote "but not with <script>" but you didn't show how the non-module script would emulate the import. If it used XHR, then CORS. But if it used generated script, then "secret-key" in the nested, generated script's URL would leak just the same, apples to apples. Right?

@annevk
Copy link
Member

annevk commented Jan 15, 2017

There is no non-module script in my scenario. Just the resource I outlined.

@BrendanEich
Copy link

BrendanEich commented Jan 15, 2017

@annevk: Your outline is not a parallel construction, it ignores the real-world use of generated and injected scripts in lieu of imports today.

This github issue's root comment posits a non-module script alternative, because that's all we have today, and if CORS is required for script type=module, then we will likely continue to have too many such scripts that generate scripts in lieu of imports, ceteris paribus.

  1. <script src=other.com/a.js>
  2. a.js injects <script src=other.com/secret.js>
  3. SW picks up secret.js URL

This is what I mean by "apples to apples". We don't get to choose the dream-state of high CORS + type=module third party adoption. We only get to optimize script type=module adoption and give developers tools to secure as they see fit. And we can definitely hamper adoption with security theater. Which is exactly the bad outcome that this issue is concerned about avoiding.

@annevk
Copy link
Member

annevk commented Jan 15, 2017

I wish we could explore this together in a more amicable matter. I keep getting the feeling you are trying to tear me down.

I think it's important to be on the same page with regards to the attack, irrespective of the tradeoffs involved.

So if the only difference with type=module is how the response is parsed, what are the potential issues? "secret" leaking is not great and it would not just happen for JavaScript resources, it would also happen for any resource that looked like one. import "secret"; doesn't seem very unique. (<script> not checking MIME types is why we started muting exceptions for cross-origin resources. Attackers used <script> to read credentialed HTML content in the past. You can now get remote debugging back through CORS.)

If we can agree on that, then there could be a discussion with regards to likelihood, requiring a MIME type, requiring CORS, etc. As I said to @dherman at some point I personally wouldn't mind leaving CORS out, but requiring a JavaScript MIME type seems important. (Although that wouldn't quite solve remote debugging, unless we somehow agree that leaking more of JavaScript resources across origins than we have done so far is acceptable. Given where Chrome stands that seems unlikely.)

@domenic
Copy link
Member

domenic commented Jan 15, 2017

(Chrome team hat on, as opposed to HTML editor hat which was on for #1888 (comment) and is generally on unless stated explicitly otherwise.)

The Chrome team, including the Chrome security team specifically, strongly believes that the presence of insecure constructs on the current web is not a reason for introducing new insecure constructs to the web. Arguments based around such lines of reasoning (i.e. "apples to apples") are not at all convincing to us.

@domenic
Copy link
Member

domenic commented Jan 15, 2017

Same-origin was buggy and underspecified (and still is)

This is a serious bug report. Could you file a separate issue describing the attack you're alluding to, and the underspecified areas with the SOP? If you're not willing to disclose in a public forum, please reach out to one or more of the editors by email.

CORS security theater

Again, if you are using this in the conventional sense of "security theater" (i.e. something like the TSA which does not actually help security), this is either a serious issue or a serious misunderstanding. Can you clarify in what sense you believe CORS's stated security benefits are just "theater"? Maybe it is based on the below misunderstanding?

SWs can see all requests, so the "leak" would apply in either the type=module or old-style script src= case. Nested imports or generated script tags or XHRed code loads or whatever, doesn't matter -- SWs see all.

This is not true. Service workers only seem same-origin resources or CORS-annotated cross-origin resources. Otherwise they get opaque responses which they cannot "see".

@annevk
Copy link
Member

annevk commented Jan 16, 2017

No, because <script src=X> would not parse or evaluate as JavaScript. You would get a masked exception (SyntaxError without the masking).

@ekr
Copy link

ekr commented Jan 16, 2017

Ah, yes. Duh.

@BrendanEich
Copy link

BrendanEich commented Jan 16, 2017

@annevk I'm striving still, and not calling anyone out for "ignorance" either :-/ . That came at me from @domenic -- and IIRC you as well.

I'm happy to explore nuanced solutions as time allows, but let's cut the b.s. -- this issue saw @domenic throw "Chrome team" weight around. Complaints about twitter bullying do not move me much in light of a big-bully dominant-share browser vendor ultimatum. If that's how this issue and who knows how many others will be decided, no point in further discussion.

When you write "complex set of tradeoffs", I'm with you. So requiring CORS for script type=module needs to consider all of those tradeoffs. That's why this issue was filed. Asking for detailed rationale instead of argument from authority got us mostly nowhere, but your scenario is good and I'm glad you sent it. I still do not see why SW and loader specs can't do same for type=module as they do for other sources of requests.

Your "something new we haven't thought of yet" is an argument for defense in depth, also good but too generic to overcome tradeoffs work by itself. CORS gives defense in depth protection against future leaks, but at what price?

It seems to me the likely price is continued majority (by any measure) use of old script src= without CORS and without modules. That's a loss. Can we avoid it, minimize the risk?

@BrendanEich
Copy link

BrendanEich commented Jan 16, 2017

@ekr: right, Script cannot produce import sentences in JS.

But push in the other direction on the degree of freedom at hand -- the option to have SW+loader specs keep non-CORS (under the assumption this issue is resolved to remove the CORS mandate for script type=module) cross-origin requests via imports from leaking, just as the SW/HTML spec does for non-CORS cross-origin requests of other kinds.

Why would we assume that the import-induced information leak must be permitted in the no-CORS alternative, when we intentionally spec to preclude equivalent-under-transpiling leaks from old-style script src= world? Or if we don't preclude, then what's the new threat? Anyway, it seems fair to raise since the opaque response idea was already used here at an earlier stage of the discussion.

@annevk
Copy link
Member

annevk commented Jan 17, 2017

I don't see where I called you ignorant. I did notice you called me that when I woke up Monday in my Twitter mentions. I'm not sure why you take your beef with Google out on me. And as we're still not on the same page and you're still combative I'm bowing out. Peace.

@BrendanEich
Copy link

BrendanEich commented Jan 17, 2017

@annevk: You're right, you didn't call me ignorant, only my pal @domenic did (but then you schooled him on opaque handles being responses not requests, lol). i still think you misread my tweet, as noted on Twitter, but I'm sorry if it came off as attacking you (which would be silly, since it was you who schooled us on the opaque handle business). I don't care about who forgot what subtle corner case; that's a sideshow and a distraction.

(In other news, David was mean to Goliath. That's one version of the story, anyway! ;-)

I'm still non-combatively interested in your thoughts on censoring non-CORS cross-origin script type=module import leaks, under the assumption CORS is not required. It could be that this is too much of a hack, I get that -- but it addresses the threat you raised, unless I'm missing something.

@BrendanEich
Copy link

BrendanEich commented Jan 17, 2017

One last thing, then I will shut up.

I'm a WHATWG founder. When MS made "the IE team picks" decisions which led to HTML and JS standards effectively or actually shutting down over ten years ago, we didn't just give up, even if we might have agreed on one particular MS decision or another. We founded the WHATWG in 2004 to get a more deliberative and less one-sided process in place to evolve the Web.

So even if I agreed that script type=module requiring CORS was the right decision, I'd still want to refrain from consequentialism (the end of safer by default justifies the means of single-vendor trump card throwing). I'd want this issue to get a better and more nuanced response prior to being closed, to weigh that "complex set of tradeoffs" mentioned in #1888 (comment).

Just saying "Chrome team picks" doesn't cut it now, any more than invoking the "IE team" fourteen years ago, or the "Firefox team" twelve years ago, to resolve an issue would have settled -- or in fact did settle -- anything. If "the Safari team" differs, this issue will be reopened. It seems to me much better to weigh the tradeoffs first, then close the issue.

Ok, I'm done. Thanks for reading this far, if you did.

@domenic
Copy link
Member

domenic commented Jan 17, 2017

In case anyone gets the wrong impression from Brendan's comments, this is not a Chrome-team unilateral decision in any way, but instead a collaborative decision between representatives from all browser engine developers (including some representatives from Mozilla, although non-Gecko parts of Mozilla such as the OP disagree). This can be seen by perusing the upthread comments, but since I know people like to link to downthread comments directly, I thought it'd be important to clarify. Brendan's preferred narrative of Chrome throwing around its marketshare here does not make any sense when confronted with the facts, and analogizing with IE shutting down web standards is not accurate or fair.

@annevk
Copy link
Member

annevk commented Jan 17, 2017

Thanks @BrendanEich.

I think my main problem with the alternative (assuming you're not okay with requiring a JavaScript MIME type, as I mentioned earlier) is that I suspect we'll forget about this hole down the road. And the reason I think that is because this is something we would have to add specifically for <script type=module>. The bypassing of the service worker for subresources.

There is one other resource type that exhibits a similar problem, CSS. And Chrome and Firefox have issues filed to consider making non-CORS-CSS subresources (so subresources of a CSS resource that was loaded without using CORS) bypass service workers, but the CSS leak is a lot more limited since it only applies to text/css-labeled resources.

So an acceptable alternative in my opinion would be deciding that resources labeled with text/css or a JavaScript MIME type better not contain secrets and tell developers that and require a JavaScript MIME type for <script type=module> fetches.

Now, not having CORS for module scripts does have a lot of downsides apart from not closing the hole, so we need to continue to offer <script crossorigin> to get CORS. You need CORS for subresource integrity, transpiling, packaging managed by a service worker (I hear a current problem with HTTP/2 is that compression does not work well across responses, so you might still want to bundle modules somehow), remote debugging, etc. So just requiring it by default is safer and also gives developers tons of benefits once they crossed the hurdle.

One other problem I can think of is that if CORS is not there by default, would <script crossorigin> have to inherit somehow? Or would JavaScript need to create new import syntax to set certain options? Or anyone that wants to use service workers for transpilers and stuff can only do that with custom loader code, for which we don't have an API (ready)?

And as I said before, it's easy to remove CORS if we have no traction after a year, it is hard to add it later.

@dherman
Copy link
Author

dherman commented Jan 18, 2017

@domenic It's frustrating to hear you claim that this was a collaborative decision but to have so many of my points consistently go unanswered, or get met with nothing more than "we're not convinced." It feels like the only way I can get attention to this issue is to get some other people involved. :(

@annevk I'm having trouble understanding this part:

I think my main problem with the alternative...is that I suspect we'll forget about this hole down the road. And the reason I think that is because this is something we would have to add specifically for <script type=module>. The bypassing of the service worker for subresources.

Can you decode that for me?

@annevk
Copy link
Member

annevk commented Jan 18, 2017

If we decide to work around the hole of import identifiers leaking to service worker by skipping the service worker for submodule identifiers, we need to add conditionals to the module fetching setup to make that happen. Then if we add a Loader API for modules, we again need to make sure that it doesn't leak submodule identifiers. Then for the resource timing API (not "something new we haven't thought of yet" but "something old we haven't thought of yet") we need to make sure it doesn't leak submodule identifiers. And on it goes. Anything we ever do with requests needs to take into account that not all requests are equal from a security perspective and we would need to design specific workarounds for the scenarios those APIs deal with.

Hope that helps.

@annevk
Copy link
Member

annevk commented Jan 18, 2017

(Note that in my alternative that I'm not a big fan of, requiring the JavaScript MIME type, we would just treat those requests as any other and leak the identifiers. But then at least the leak is limited to JavaScript and we don't have a fragile system.)

@dveditz
Copy link
Member

dveditz commented Jan 19, 2017

The Mozilla folks are reviewing this design and are not uniformly convinced that CORS is necessary for a default no-credentials, content-type restricted (which we already wanted) request. Obviously we have not reached internal consensus but didn't want silence to be interpreted as agreement.

@CalinZBaenen

This comment was marked as abuse.

@CalinZBaenen
Copy link

CalinZBaenen commented Jul 24, 2022

My last comment was marked with disruptive comment, which is fair, and my thread is shown here, but I thought I would leave an update comment anyways.

I made a comprehensive reasoning as to why module-scripts should be allowed, #8121, and it basically says what you've said here, but specifically that CORS is unneeded when int file://. - And if we want to broaden this to your scope it should be made an option.
It can be boiled down to a list of eleven reasons, which I have made in a comment to my Issue.

I think the biggest benefit of my, and by extension @dherman's suggestion, is that it allows and promotes the use of modular code in all of the contexts JavaScript. Plus, it works on the browser server-side, so it should be easy to parity in a client-side context, such as in the file:// protocol.

@CalinZBaenen
Copy link

CalinZBaenen commented Dec 1, 2022

The web's fundamental security model is the same origin policy. We have several legacy exceptions to that rule from before that security model was in place, with script tags being one of the most egregious and most dangerous. (See the various "JSONP" attacks.)

Many years ago, perhaps with the introduction of XHR or web fonts (I can't recall precisely), we drew a line in the sand, and said no new web platform features would break the same origin policy. The existing features need to be grandfathered in and subject to carefully-honed and oft-exploited exceptions, for the sake of not breaking the web, but we certainly can't add any more holes to our security policy.

That's why, from our perspective, making module scripts bypass the CORS protocol (and thus the same-origin policy) is a non-starter. It's not about a specific attack scenario, apart from the ones already enabled by classic scripts; it's about making sure that new features added to the platform don't also suffer from the past's bad security hygiene.

@domenic, is this actually ever mentioned that <script>s are left in the file:-protocol because of grandfathering in the WHATWG HTML Specification? Because that seems like a pretty important thing to leave out.
I personally couldn't find anything using LibreWolf's pagesearch, nothing with "grandf" is found.

(*Additionally, it seems like people are using JavaScript in the file: protocol for more than just backwards compatibility nowdays, which should have been adapted to.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests