WICG / import-maps

How to control the behavior of JavaScript imports
https://html.spec.whatwg.org/multipage/webappapis.html#import-maps
Other
2.68k stars 69 forks source link

Support subresource integrity #174

Closed bates64 closed 5 years ago

bates64 commented 5 years ago

It would be incredibly useful for import maps to support subresource integrity hashes that are checked against similar to <script integrity=""/>. This is extra important because one of the primary goals of import mapping is to support delivery from 3rd party CDNs (such as unpkg) -- for security, SRI is almost vital when using an external CDN.

This might come in the form:

{
  "imports": {
    "cool-module": [
      { "url": "https://unpkg.com/cool-module@1.0.0?module", "integrity": "sha384-..." },
      "/node_modules/cool-module/index.js"
    ]
  }
}

Note the new option of a { url, integrity } object in place of a string URL on its own.

Alternatively, a top-level integrity object mapping URL to SRI hash might be a better fit as it is backwards-compatible with existing browser and polyfill implementations, and supports adding SRI for nested imports like cool-module/file.js.

domenic commented 5 years ago

Heya, this is out of scope for this repository. See discussion at https://github.com/WICG/import-maps#supplying-out-of-band-metadata-for-each-module and the previous similar iissue, https://github.com/WICG/import-maps/issues/99.

I'll close this since we won't be working on it in this repository, but I'm happy to continue discussing in the close thread.

shannonmoeller commented 4 years ago

+1 to the idea of using import maps for subresource integrity as import in JS and @import in CSS have no way to specify a sha. Import maps feel like a natural fit for this. Is there documentation, discussion, or an alternate proposal on the topic elsewhere, if not here or #99?

brettz9 commented 4 years ago

The slides at https://docs.google.com/presentation/d/1qfoLTniLUVJ5YNFrha7BaVumAnW0ZgcCfUU8UbyyuYY/edit#slide=id.g1f527b5ce9_0_108 (starting at slide 13) were helpful toward explaining the down-side of modifying the import syntax.

I may still be inadequately informed in my comments here, but have a few thoughts...

Isn't integrity mostly of use with CDN's, which are more likely to be hosting fixed versions (and caching is already an issue there in one sense with any new version causing need for a separate cache)? While CDN's might not currently suffer from transitive dependencies causing breakage, I'd think in some way this would be a feature, as it would help protect against a depender file accidentally expressed to expect an outdated resource or resource chain.

And though there is the difficulty of manually managing integrity meta-data inline, tooling could no doubt help with this, e.g., to get checksums from the likes of local npm copies and expect the same on the CDN, and then rebuilding all of the local ones.

In addition, the out-of-band solution introduces its own additional can-of-worms in that it would break modularity, requiring storage of meta-data on a resource in a manner unconnected directly with that resource.

That all being said, unlike the other meta-data attributes (e.g., cross-origin, etc.) which have an impact on how the application works, integrity might be a special case in that it is just pass-or-fail and the preparer may wish to do their own separate calculation/verification of the hashes anyways--e.g., they could, like custom resolutions in yarn, let one avoid being locked in to a vulnerable dependency. (npm, for a perhaps useful comparison, does its own out-of-band tracking of checksums--not expecting packages to manage this themselves.)

And by the meta-data being stored out-of-band, diff noise would be avoided (though admittedly source files might not be including this meta-data themselves even if dist files were to store the data in-band.)

So maybe the solution is for integrity to be out-of-band, and other meta-data as a syntax change?

WesleyAC commented 2 years ago

@domenic, do you know of any current discussion on this? It's been a couple years, and it seems like there's still no way to do this.

Here's my situation:

It seems like there's currently no way to do this? Is there anywhere you know of where discussion is happening on this? If not, do you know of somewhere that it would be productive to restart this discussion?

WesleyAC commented 2 years ago

I should note for other wanderers that <link type="modulepreload" integrity="..." ... may work for some usecases, but AFAICT not for mine — I don't see a way to tell the browser that the preloading is just so that it knows the integrity hash, but not to actually load the file over the network until it's needed. Possibly a new attribute for link specifying that would be a good solution? (Or perhaps I'm missing an existing one that already does this)

I guess a "solution" might be to write a wrapper around import that injects a link tag onto the page before calling import? That seems like a awful hack for something that should already exist, though.

guybedford commented 2 years ago

@WesleyAC thanks for poking at this, that's a great summary. Moving forward it seems we have three options:

  1. Have a link preload for not actually preloading. See eg https://lists.w3.org/Archives/Public/public-webappsec/2021Mar/0002.html.
  2. Include integrity in the import map itself. See eg https://github.com/guybedford/import-maps-extensions#integrity
  3. Rely on bundlers that perform dynamic import wrapping, although this will tie cache digests to sources unless that technique can in turn use a bundle manifest, say eg a <script type="bundle-manifest"> that the bundler can read.

I would also really appreciate knowing which way to go here - I'm personally happy to work on specifying any standards work here, it just depends on where the implementation direction lands.

shannonmoeller commented 2 years ago

fwiw, I'm personally a fan of 2. as it keeps the url and the sha in the same place and lets you provide the integrity sha of dependencies of dependencies.

There is perhaps room for a fourth option using import assertions, but that seems out of scope for import maps:

import { camelCase } from 'https://unpkg.com/lodash' assert {
  integrity: "sha384-...",
  crossorigin: "anonymous",
};
domenic commented 2 years ago

Note that the most recent discussion are in #221; in particular see my thoughts in https://github.com/WICG/import-maps/issues/221#issuecomment-943735957.