-
Notifications
You must be signed in to change notification settings - Fork 370
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
HTML, CSS, and JSON modules shouldn't solely rely on MIME type to change parsing behavior #839
Comments
I think there's two separate parts to this:
I personally think the second one should be part of For the first one maybe we could extend the |
I believe this functionality is required in polyfilling, to support browsers not yet supports HTML/JSON/CSS modules, a server can just respond the corresponding JavaScript file that wrapping original content to default export, which could provide a consistent code style at consumer-side. |
Weakening the security model for the sake of polyfilling is an unacceptable trade off in our view. |
Imports are inherently dangerous, and this is why CSP allows for restricting the origin for scripts. That should apply to all imports, regardless of type. Importing JSON should only be done for trusted sources, and shouldn't in general be done for calling third party APIs (and arguably shouldn't be done for 1st party APIs if you don't want your module graph to fail to load if the API call fails). Regarding server-side polyfills, this should still work if the client sends the appropriate |
Given that many websites don't use CSP correctly, relying on websites to correctly deploy CSP to get the right security behavior is not a great plan. Furthermore, today, if you were to fetch JSON via XHR or fetch API and parse it via We believe this security issue is a show stopper issue for HTML, CSS, and JSON modules. |
Yeah, Mozilla does as well. Importing non-scripts should be safe by default. (If HTML modules end up executing script they might not necessarily be problematic.) |
What is the counter proposal? |
I think @justinfagnani's point here is interesting and I want to second it. Even aside from security concerns, JSON imports seem like the wrong tool for consuming non-first-party JSON/CSS. If the request 404's or if, say, the JSON has a parse error, the entire module graph will fail to instantiate/execute. |
That doesn't apply to |
This might actually be what you want in some cases, e.g. if a critical resource does fail to load then you don't want to waste resources evaluating a bunch of modules you don't need. You can always use |
Regardless of whether it's a good idea or not, some web developers are inevitably going to do it. We shouldn't be adding a new foot gun to the Web so that authors can avoid using it in certain situations to avoid creating a new security surface. |
I can only second @rniwa here, @justinfagnani's point included a lot of "should/shouldn't", and we all know how that goes. Importing non-scripts must be safe by default. |
Is it OK for WebAssembly modules to have parsing behavior based on their MIME type? That's what the current proposal does. |
Are there any proposals / ideas that could solve these issues? At the risk of suggesting something naive, could the file extension be the way that the import statement specifies its expected module type? // both the file extension and mime type must be present for the non-script module to load
import 'file.json'
import 'file.css'
import 'file.html The obvious limitation of this approach is that you can't load json, css, and html modules from urls without the proper file extension. The advantage is that it doesn't require a rework of import statements and import maps to make html, css, and json modules work. |
Apart from plugins there's no precedent for putting meaning in file extensions within the web, I don't think we should start here. |
That’s not ideal but less problematic because the expectation of loading WASM & JS are similar: they execute arbitrary scripts. It’s not so with CSS & JSON. |
As explained at WICG/webcomponents#839 the current setup is insecure. This reverts db03474.
If we had syntax in JavaScript for asserting the MIME type (mandatory for JSON modules, and optional for JavaScript), would that address this concern? If so, we can look into this issue in TC39; I don't think we have considered it before. As a strawperson, it could look like this: import document from "./foo.json" with mime: "application/json"; This could be a basis for adding sending metadata to the host environment (HTML, Node.js, etc). Thoughts? Did people have other specific ideas for what this should look like? |
Nothing concrete was discussed, but yeah, something like that would address the concern. And equivalent for |
The author is the only true arbiter of the parse goal of content; would this be an assertion, or would it change the parsing like script |
@ljharb I imagine we would continue to use MIME type in conjunction with the declaration within JS. That's why I used the word "assertion". |
how about the CSP idea but the default is disallow instead of allow? I think the layering of extending import syntax is a bit iffy, since it adds host-specific semantics to an otherwise generic bit of code, and then random hosts have to be like "wait what do i do with this" |
It doesn't really seem host-specific to be able to import JSON without that resulting in script execution later on. |
as an example, node requires you to write |
Right, somehow, this is syntactically redundant in environments where the interpretation is implied by the module specifier's suffix already. The web doesn't have a tradition of making such judgements. I suppose the analogous (and unprecedented?) thing here would be something like requiring that, if the MIME type is If we require this syntax for JSON modules on the web, I think there is some chance that a common authoring format will omit the assertions, and tools will insert it when generating web output as part of a build process. But there is also a chance that we can convince most people to write this directly. |
sorry, to be more direct with what i'm trying to say: given security is host specific, shouldn't this assertion be out-of-band from the import? at worst you would have hosts ignoring a check people expected would be enforced. |
Inferring meaning from a file extension is incompatible with the web's architecture. Requiring out-of-band annotations seems like it would create such bad ergonomics the feature would effectively not be used on the web. |
Is there a solution discussed anywhere already that can take inspiration from import maps to provide loaders declared out of band? |
@tilgovi I think OOB has significant DX and usability downsides. See my comment here: tc39/proposal-import-attributes#13 (comment) |
In think about this a bit today... WASM doesn't have access to the DOM, correct? So an author could assume a WASM module has restricted access if it's not explicitly passed functions to allow it DOM access. If a file previously served as |
The not-yet-implemented-in-any-browser Wasm/ESM integration proposal gives Wasm the same level of privilege as JavaScript by design. This proposal allows importing arbitrary JS modules (including cross-origin), which could export functions that manipulate the DOM but have signatures which are just based on numerics, so it would be importable and usable from Wasm. The goal is to allow transparent interaction. |
If this is about validating the input given by import, then could the import be augmented with function? import someJson from "./some.json" with JSON.Parse;
import someTextFile from "./some.txt" with String;
// Going further, one could define own parser:
function MyParser(content, url, mimetype) {
let sheet = new CSSStyleSheet();
sheet.replaceSync(content);
return sheet;
}
import someCssStylesheet from "./someother.css" with MyParser; Having the parser as a plain function one can define, would allow to introduce some other logic easily in future. It's not uncommon to have different ways to parse e.g. It would even allow returning a module like result, because you could return object from your parser function e.g. function AnotherParser(content, url, mimetype) {
// ...
return { justThis: "Hello world", orThis: 5 };
}
import { justThis, orThis } from "./interesting-url" with AnotherParser; It's of course debatable what argument should the parser get? Some object with more details including mime type, a string, and possibly the url? |
With the advancement of import assertions to Stage 3 in TC39, can we consider this issue resolved? |
@dandclark I personally still don't see any info of how that would be resolved when there's no assertion. Will this: import json from "./foo.json" still use MIME-type? I opened this question in the proposal, calling it default assertions: tc39/proposal-import-attributes#101 |
@jerrygreen |
Yeah, let's close this. In response to this issue:
|
Sorry for commenting on a closed issue, but does that mean HTML/JSON/CSS Modules can only land after import assertion gets to Stage 4? In other words, is Import Assertion the blocker on HTML/JSON/CSS Modules? |
Stage 3 is fine for integration with the HTML Standard. |
As we discussed in TPAC 2019 Web Components session, the current proposal / spec of HTML, CSS, and JSON modules do not specify the type of content in the import statement.
This is problematic because an import statement that intended to load CSS or JSON and not execute arbitrary scripts could end up executing scripts if the destination server's MIME type got changed or the destination server get compromised.
In general, we've made so that the importer of any content can specify how the imported content should be parsed & processed. This is one of the motivations for adding CORS fetch for JSON as opposed to JSONP for example.
The text was updated successfully, but these errors were encountered: