- From: Jeffrey Yasskin <jyasskin@google.com>
- Date: Mon, 21 Sep 2020 12:11:35 -0700
- To: Krzysztof Kotowicz <koto@google.com>
- Cc: Hayato Ito <hayato@google.com>, Yoav Weiss <yoavweiss@google.com>, Mike West <mkwst@google.com>, Ryosuke Niwa <rniwa@apple.com>, public-web-perf <public-web-perf@w3.org>
- Message-ID: <CANh-dXkkQgHYR5pcLLGxXDsaqFS9kBV56FiJ+Y8ffgfoVcWXzA@mail.gmail.com>
On Mon, Sep 21, 2020 at 7:53 AM Krzysztof Kotowicz <koto@google.com> wrote: > > > On Fri, Sep 18, 2020 at 8:04 PM Jeffrey Yasskin <jyasskin@google.com> > wrote: > >> On Fri, Sep 18, 2020 at 1:29 AM Krzysztof Kotowicz <koto@google.com> >> wrote: >> >>> >>> >>> On Fri, Sep 18, 2020 at 9:08 AM Hayato Ito <hayato@google.com> wrote: >>> >>>> Let me update the status. >>>> >>>> We are considering using <script> elements as a declarative form [1], >>>> instead of <link> elements, to address security concerns. >>>> However, before proceeding this way, we'd like to confirm one thing; >>>> Can't we use <link> elements even if we limit subresources loaded from the >>>> bundle only to the same-origin resources to the bundle's URL? >>>> >>>> Let me explain with an example: >>>> >>>> Suppose we have a bundle, "https://example.com/sub.wbn", which >>>> includes the following three resources: >>>> - https://example.com/a.png >>>> - https://example.com/b.png >>>> - https://other.com/c.png >>>> >>>> We use this bundle as follows: >>>> >>>> <link rel=webbundle href="https://example.com/sub.wbn" >>>> resources="https://example.com/a.png https://example.com/b.png >>>> https://other.com/c.png"> >>>> <img src=https://example.com/a.png> >>>> <img src=https://example.com/b.png> >>>> <img src=https://other.com/c.png> >>>> >>>> In this case, >>>> - We load a.png and b.png from the bundle because their origins, >>>> https://example.com, are the same to the bundle's origin, >>>> https://example.com. >>>> - however, we don't load c.png from the bundle because its origin, >>>> https://other.com, is different from the bundle's origin, >>>> https://example.com. >>>> >>>> This means that a bundle is effectively used to package subresources in >>>> the one same origin. The different origin subresources are unlikely to be >>>> packaged in one bundle. >>>> >>>> Suppose that we limit subresource loading this way, does security >>>> concerns still apply to the usage of <link> elements? >>>> >>>> >>> Thanks for the update! I think there are still some security concerns >>> remaining. The concerns are much smaller of course (and limiting to the >>> origin is a smart idea!), but I worry that the risk is not really about the >>> origins here, but rather about being able to change the content under a >>> given URL (without, say, a service worker installation) on the embedding >>> page. It "feels" like it should require a capability of injecting a script >>> element to the embedder. >>> >>> To make sure I understand the setup correctly - in order to have a >>> correct (i.e. able to replace the resources) bundle served from >>> example.com, one needs to have the capability to serve anything under >>> example.com (e.g. the TLS keys)? If the attacker needs to have anything >>> less than that, then the potential attack is still possible for shared >>> origins (e.g. https://foo.example/~alice/bundle.wbn could replace >>> https://foo.example/~bob resources requested on another page). The >>> shared origin is usually not an issue, as Alice can trivially XSS Bob, but >>> here the attack (replacing the resources by injecting a <link>) is >>> happening on _another_ page, e.g. a https://i.only.trust.bob.example/. >>> >> >> As mentioned in >> https://github.com/WICG/webpackage/issues/580#issuecomment-679473747, we >> avoid this particular attack by adopting a path restriction similar to the >> one Service Workers use. So, say there's a bundle at >> https://foo.example/~alice/bundle.wbn. It contains the following >> resources: >> >> 1) https://foo.example/~alice/bundle.wbn/script1.js (doesn't work on a >> filesystem, but a web server could serve it) >> 2) https://foo.example/~alice/script2.js >> 3) https://foo.example/~bob/script3.js >> >> The current proposal says it's authoritative for (1) and (2) by default, >> but needs a response header (similar to Service-Worker-Allowed) to be >> authoritative for (3). We could make it authoritative for just (1) or for >> nothing at all by default, and still allow the header to expand the >> authoritative scope. >> >> > Thanks for clarifying that! Glad to know that the attack was taked into > consideration! I would still have somewhat better sleep if controlling > which scripts run on a page (or blocking ones from running) required > injecting a <script> node. > Note that a `<link rel=preload href="the_script.js" integrity="sha256-WrongValue">` also blocks the script from running. I believe the new risk is around changing what scripts run if the bundled and non-bundled scripts are different for some reason, maybe because one is stale or a server allows the attacker to write new content into a directory that contains (directly or indirectly) scripts. Jeffrey > It just feels too powerful, and similar in capabilities to WICG import > maps <https://github.com/WICG/import-maps>. I worry, perhaps too much, > that we might be enabling future bugs through this, as that behavior is > quite surprising. But that's not a hard NO at this point. > > >> Jeffrey >> >> >>> [1] POC CL: >>>> https://chromium-review.googlesource.com/c/chromium/src/+/2402927 >>>> >>>> On Mon, Aug 31, 2020 at 4:15 PM Hayato Ito <hayato@google.com> wrote: >>>> >>>>> Regarding <script> as a declarative form, It seems there is a >>>>> similar proposal, <script type="importamap">. >>>>> >>>>> (copy/pasted from https://github.com/WICG/import-maps) >>>>> >>>>> <script type="importmap"> >>>>> { >>>>> "imports": { >>>>> "moment": "/node_modules/moment/src/moment.js", >>>>> "lodash": "/node_modules/lodash-es/lodash.js" >>>>> } >>>>> } >>>>> </script> >>>>> >>>>> We'll report back once we know the status of <script >>>>> type="importmap">. We might learn from there. >>>>> >>>>> On Fri, Aug 28, 2020 at 10:55 PM Yoav Weiss <yoavweiss@google.com> >>>>> wrote: >>>>> >>>>>> Krzysztof and I talked about this offline and reached some >>>>>> conclusions: >>>>>> >>>>>> - `<script>` seems like the right declarative home for this - to >>>>>> make sure it's defended against similarly to other XSS vectors >>>>>> - A declarative solution can still be racy if specified naively, >>>>>> and the processing model should make sure that it is not (e.g. by not >>>>>> loading the bundle if resources covered by it were already fetched) >>>>>> >>>>>> >>>>>> On Fri, Aug 28, 2020 at 12:42 PM Krzysztof Kotowicz <koto@google.com> >>>>>> wrote: >>>>>> >>>>>>> I understand that. My question is, are we actually avoiding races if >>>>>>> we kept, say, link element? >>>>>>> >>>>>>> <script> >>>>>>> document.head.appendChild(scriptWithBundleUrl); >>>>>>> document.head.appendChild(webBundleLink); >>>>>>> </script> >>>>>>> >>>>>>> On Fri, Aug 28, 2020 at 12:11 PM Yoav Weiss <yoavweiss@google.com> >>>>>>> wrote: >>>>>>> >>>>>>>> Think of the following HTML, based on Hayato's example: >>>>>>>> ``` >>>>>>>> <link rel=stylesheet href="https://www.example.com/unbundled.css"> >>>>>>>> <script> >>>>>>>> document.webbundles.add({ >>>>>>>> href: 'https://www.example.com/foo.wbn >>>>>>>> <https://www.exmaple.com/foo.wbn>', >>>>>>>> resources: ['https://www.example.com/a.js >>>>>>>> <https://www.exmaple.com/a.png>', 'https://www.example.com/b.css >>>>>>>> <https://www.exmaple.com/b.css>', ...] >>>>>>>> }); >>>>>>>> </script> >>>>>>>> <link rel=stylesheet href="https://www.example.com/b.css"> >>>>>>>> <script src="https://www.example.com/a.js"> >>>>>>>> ``` >>>>>>>> >>>>>>>> The browser (all browsers, in subtly different ways) would take the >>>>>>>> HTML tokens, scan them and speculatively preload a.js and b.css based on >>>>>>>> that, before executing the inline script (which is blocked on the style >>>>>>>> above it). >>>>>>>> Aside: I believe that even without the blocking "unbundled" style >>>>>>>> the race would be often lost. May merit testing in the different browsers. >>>>>>>> >>>>>>>> While we could ask developers to not do that, and always trigger >>>>>>>> request for bundled resources from JS, that would have significant >>>>>>>> ergonomics, adoption and performance implications, and I'd much rather we >>>>>>>> don't go that route. >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> On Fri, Aug 28, 2020 at 12:01 PM Krzysztof Kotowicz < >>>>>>>> koto@google.com> wrote: >>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> On Fri, Aug 28, 2020 at 11:49 AM Yoav Weiss <yoavweiss@google.com> >>>>>>>>> wrote: >>>>>>>>> >>>>>>>>>> If we want WebBundles to fit into today's pages (which e.g. >>>>>>>>>> include `<script src>` tags), we need an imperative mechanism to load them >>>>>>>>>> and tell the browser about the resources they contain. >>>>>>>>>> An imperative mechanism to load them would only be effective for >>>>>>>>>> dynamically loaded resources, which are inherently slower to discover. It >>>>>>>>>> would be a shame if we ended up encouraging that pattern. >>>>>>>>>> >>>>>>>>>> Would moving away from `<link>` to e.g. `<base>` (as Mike >>>>>>>>>> suggested) or `<script type=bundle>` address your concerns? >>>>>>>>>> >>>>>>>>> >>>>>>>>> I would prefer base or script, yes. But is the raciness problem >>>>>>>>> solved, given that DOM is mutable from JS? That would need to be addressed >>>>>>>>> anyhow if I understand correctly. >>>>>>>>> >>>>>>>>>> >>>>>>>>>> On Fri, Aug 28, 2020 at 11:33 AM Krzysztof Kotowicz < >>>>>>>>>> koto@google.com> wrote: >>>>>>>>>> >>>>>>>>>>> The DOM tree can also change dynamically. If the element that >>>>>>>>>>> controls the bundle loading is inserted via JS, would that >>>>>>>>>>> also affect raciness? If so, there's little way around it, short of >>>>>>>>>>> ignoring the behavior when added dynamically (which might be surprising for >>>>>>>>>>> authors). >>>>>>>>>>> >>>>>>>>>>> On Fri, Aug 28, 2020 at 10:58 AM Yoav Weiss < >>>>>>>>>>> yoavweiss@google.com> wrote: >>>>>>>>>>> >>>>>>>>>>>> An imperative mechanism to load bundles would be inherently >>>>>>>>>>>> racy - the preloadScanner would not be aware of it, and can kick off script >>>>>>>>>>>> requests before their bundles are discovered. >>>>>>>>>>>> >>>>>>>>>>>> If `<link>` is a risky choice here, I'm fine with a different >>>>>>>>>>>> tag to do the same. I have no strong opinion regarding what would be a good >>>>>>>>>>>> alternative. >>>>>>>>>>>> >>>>>>>>>>>> On Fri, Aug 28, 2020 at 10:44 AM Mike West <mkwst@google.com> >>>>>>>>>>>> wrote: >>>>>>>>>>>> >>>>>>>>>>>>> I don't have a strong opinion about the mechanism, but I do >>>>>>>>>>>>> think the risk ascribed to the `<link>` approach is real. >>>>>>>>>>>>> >>>>>>>>>>>>> If declarative mechanisms are preferred, I wonder if an >>>>>>>>>>>>> extension to `<base>` would be more appropriate here than an extension to >>>>>>>>>>>>> `<link>`. `<base>` already affects resource loading across the page (in >>>>>>>>>>>>> kinda terrible ways, but still!), and so already needs to be addressed by >>>>>>>>>>>>> folks who aim to sanitize user input. >>>>>>>>>>>>> >>>>>>>>>>>>> It also is suggested to be invalid outside of `<head>`, which >>>>>>>>>>>>> would be similarly helpful if browsers implemented that as a requirement; >>>>>>>>>>>>> there doesn't seem to be a WPT for it, and Chromium at least would fail. >>>>>>>>>>>>> >>>>>>>>>>>>> -mike >>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>>> On Fri, Aug 28, 2020 at 9:18 AM Hayato Ito <hayato@google.com> >>>>>>>>>>>>> wrote: >>>>>>>>>>>>> >>>>>>>>>>>>>> Hi Ryosuke. Thanks for sharing concerns. >>>>>>>>>>>>>> >>>>>>>>>>>>>> I'm wondering if we have imperative JS APIs which >>>>>>>>>>>>>> are *equivalent* to declarative one, some of the security concerns will be >>>>>>>>>>>>>> addressed? >>>>>>>>>>>>>> >>>>>>>>>>>>>> Imperative JS APIs can be something like: >>>>>>>>>>>>>> >>>>>>>>>>>>>> <script> >>>>>>>>>>>>>> // Tentative ideas. API surfaces do not matter for now. >>>>>>>>>>>>>> document.webbundles.add({ >>>>>>>>>>>>>> href: 'https://www.exmaple.com/foo.wbn', >>>>>>>>>>>>>> resources: ['https://www.exmaple.com/a.png', ' >>>>>>>>>>>>>> https://www.exmaple.com/b.css', ...] >>>>>>>>>>>>>> }); >>>>>>>>>>>>>> </script> >>>>>>>>>>>>>> >>>>>>>>>>>>>> # Then, UA will try to load 'https://www.exmaple.com/a.png' >>>>>>>>>>>>>> (the same origin resource of the bundle) from the specified bundle, instead >>>>>>>>>>>>>> of the network. >>>>>>>>>>>>>> <img src='https://www.exmaple.com/a.png'> >>>>>>>>>>>>>> >>>>>>>>>>>>>> Is my understanding correct? >>>>>>>>>>>>>> >>>>>>>>>>>>>> On Fri, Aug 28, 2020 at 2:30 PM Ryosuke Niwa <rniwa@apple.com> >>>>>>>>>>>>>> wrote: >>>>>>>>>>>>>> >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> On Aug 27, 2020, at 1:05 PM, Jeffrey Yasskin < >>>>>>>>>>>>>>> jyasskin@google.com> wrote: >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> Hi Web Perf experts, >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> We're working >>>>>>>>>>>>>>> <https://www.chromestatus.com/feature/5710618575241216> on >>>>>>>>>>>>>>> using (unsigned) web bundles to help with preloading subresources. The >>>>>>>>>>>>>>> current design is at >>>>>>>>>>>>>>> https://github.com/WICG/webpackage/blob/master/explainers/subresource-loading.md, >>>>>>>>>>>>>>> but roughly the idea is that a page would build a bundle of the >>>>>>>>>>>>>>> subresources it intends to use and put a >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> <link rel="webbundle" href="/the_bundle.wbn" >>>>>>>>>>>>>>> scope="/resources"> >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> with their other preloads (or one of several variations). >>>>>>>>>>>>>>> After that, >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> <script src="/resources/foo.js"> >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> would find the version in the bundle instead of having to >>>>>>>>>>>>>>> fetch it independently. >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> This isn’t about preloading is it? This will actually affect >>>>>>>>>>>>>>> the resource being used by that script element. preload doesn’t do that so >>>>>>>>>>>>>>> this is a pretty different feature. >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> In https://github.com/WICG/webpackage/issues/580, Krzysztof >>>>>>>>>>>>>>> worries that adding any new way for a <link> tag to affect script loading >>>>>>>>>>>>>>> is a security risk, because pages may not be as careful about preventing >>>>>>>>>>>>>>> users from injecting <link> tags as they are about <script> tags. Instead, >>>>>>>>>>>>>>> he suggests using a Javascript API to tell the browser to preload >>>>>>>>>>>>>>> subresources using a bundle. >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> That would be a pretty serious security risk. Putting all >>>>>>>>>>>>>>> other objections against web packaging / web bundles aside, this will be a >>>>>>>>>>>>>>> pretty big show stopper. >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> - R. Niwa >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> -- >>>>>>>>>>>>>> Hayato >>>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> -- >>>>>>>>>>> koto@ / Krzysztof Kotowicz / Google >>>>>>>>>>> >>>>>>>>>> >>>>>>>>> >>>>>>>>> -- >>>>>>>>> koto@ / Krzysztof Kotowicz / Google >>>>>>>>> >>>>>>>> >>>>>>> >>>>>>> -- >>>>>>> koto@ / Krzysztof Kotowicz / Google >>>>>>> >>>>>> >>>>> >>>>> -- >>>>> Hayato >>>>> >>>> >>>> >>>> -- >>>> Hayato >>>> >>> >>> >>> -- >>> koto@ / Krzysztof Kotowicz / Google >>> >> > > -- > koto@ / Krzysztof Kotowicz / Google >
Received on Monday, 21 September 2020 19:12:02 UTC