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

Allow guarding (dynamic) module imports - a type for module specifiers #117

Closed
koto opened this issue Jan 17, 2019 · 7 comments
Closed

Allow guarding (dynamic) module imports - a type for module specifiers #117

koto opened this issue Jan 17, 2019 · 7 comments

Comments

@koto
Copy link
Member

koto commented Jan 17, 2019

Script modules are here i.e. there is a way of loading additional code from a URL to your application (previously you'd just append a new script, or eval). These come in a few flavors:

Flavor Syntax Status
standard import import {foo} from 'url' ECMA standard
dynamic import import(foo).then() TC39 stage 3
HTML modules import {foo} from 'a.html' proposal

These new code loading methods introduce a few interesting challenges:

  1. There's no built in mechanism to add metadata to module names (~URLs). For example, there's no way to pass a nonce or a hash explicitly.
  2. Apart from the dynamic import, there's no way to change what's being imported at runtime. Imports are parsed, loaded and linked before the execution of the module happens.

For CSP side of things, this realistically means that only the script-src whitelist can somehow guard which modules are allowed to be run (example problem). I'm not sure if and how Trusted Types can offer something here as well, given that they are a runtime feature.

Mentioning a related issue as well, as it seems these concerns (code isolation, module limitations) are raised by other folks as well.

cc @arturjanc who raised the issue.

@koto koto added the spec label Jan 17, 2019
@koto
Copy link
Member Author

koto commented Jan 18, 2019

There actually are some prior ideas about point 1 (adding metadata): https://discourse.wicg.io/t/specifying-nonce-or-integrity-when-importing-modules/1861

If these were implemented, at least the nonce or hash value could be generated and inserted server-side.

That still doesn't solve point 2. (Trusted Types are at runtime), unless there's some code that can run in a non-module script first that populates the whitelist, e.g.

<script>
TrustedTypes.allowedScriptModules.push(modulePolicy.createTrustedScriptURL(foo))
TrustedTypes.allowedScriptModules.push(modulePolicy.createTrustedScriptURL('bar'))
</script>
<script type=module>
import {baz} from 'bazinga' // only works if allowedScriptModules contains 'bazinga'
</script>

@koto
Copy link
Member Author

koto commented Jan 21, 2019

https://github.com/WICG/import-maps just surfaced and looks like an interesting mechanism to control / guard modules used by the application. There's two important issues though:

  • no whiltelisting mode issue
  • the map is present in a document (in a <script type=importmap> node), so it's yet another reflected XSS sink (and even a DOM XSS sink, as these can be modified at runtime). Maybe it's fine - it's a script after all.

@mikesamuel
Copy link
Collaborator

@koto, I'll play around to see whether there's a way to whitelist by having a single unscoped mapping like / to something like about:invalid and then using scopes to map specific other paths to override more specific patterns.

@mikesamuel
Copy link
Collaborator

Update

Since #117 (comment) dynamic import has been accepted as stage 4 and will be part of EcmaScript 2020.

Stage 0 Dynamic Import Host Adjustment builds on that to allow vetting, and applying default policies to the argument to import(...).

@mikesamuel
Copy link
Collaborator

Open question: What is a conforming argument to import(...)?

Perhaps a TrustedScriptURL should be allowed.

Not all moduleSpecifiers are necessarily URLs though.
The Standard Library Proposal covers some of the discussions about non-URL specifiers:

NPM Style

The Node Package Manager (NPM for short) has an established format for importing packages published to a central registry. The format allows packages to be grouped under organizations and this could be leveraged as a prefix for the JavaScript standard library:

import { ... } from "@std/SomeStandardModule";

The import maps proposal distinguishes between "URL-like" specifiers but leaves open that some specifiers may not be URL-like.


Defining a type TrustedModuleSpecifier would allow:

  • Treating TrustedModuleSpecifier values as privileged inputs to import(...) regardless of whether the content string is URL-like or not.
  • Optionally treating TrustedScriptURL's as privileged URL-like inputs to import(...).

If both a new TrustedModuleSpecifier and TrustedScriptURL are allowed, then when applying the default policy to a raw string, do we fallback from one of (createModuleSpecifier, createScriptURL) to the other?

@koto
Copy link
Member Author

koto commented Aug 11, 2019

The neccessary primitive in the language to be able to guard module imports is tracked in the dynamic import host adjustment TC39 proposal.

@koto koto added the tc39 label Aug 11, 2019
@koto koto changed the title Should we guard module imports? Allow guarding (dynamic) module imports - a type for module specifiers Aug 11, 2019
@koto
Copy link
Member Author

koto commented Mar 2, 2020

Closing until after we have the necessary ECMAScript bits.

@koto koto closed this as completed Mar 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants