w3c / ServiceWorker

Service Workers
https://w3c.github.io/ServiceWorker/
Other
3.63k stars 314 forks source link

`<iframe sandbox />` + SW #1390

Open Gozala opened 5 years ago

Gozala commented 5 years ago

Hi,

It seem today implementations across major browsers do not seem to delegate request from the document inside <iframe sandbox="allow-same-origin" src="./inner" /> to the SW controlling the embedded even if it falls under the same scope. Same is true if srcdoc is used.

From what I can tell spec does not seem to specify behavior here & intuitively I would expect that to behave differently from what implementations seem to converge on.

On a related note I would like to make a case for <iframe sandbox> + SW combination that would allow embedded to control networking of the embedded document, where embedder and embedded document are from the same origin & without allow-same-origin. (maybe that's what srcdoc should do ?)

The use case being - Site wishes to load user uploaded content even if offline (think jsfiddle or dropbox). However site also doesn't trust uploaded content enough to share origin & storage / permissions shared across them.

I believe some setup like <iframe sandbox service-worker="./service.js" src="./inner"> could be an effective way to provide such behavior.

wanderview commented 5 years ago

I believe we have decided to allow service workers to control sandboxed iframes with allow-same-origin. As you say, though, the implementations have not all caught up to this decision.

Also, we have previously decided that about:srcdoc and about:blank should inherit their controller from the parent context. This is implemented in firefox, but not in chrome so far. Not sure about other browsers.

Gozala commented 5 years ago

Also, we have previously decided that about:srcdoc and about:blank should inherit their controller from the parent context. This is implemented in firefox, but not in chrome so far. Not sure about other browsers.

Do you mean srcdoc / about:black + allow-same-origin or is later not required ? In my experience Firefox (Nightly) as other browsers don't seem to do that nor with allow-same-origin nor without. Do you by chance have tracking bug for it I can try followup there.

If allow-same-origin is required for srcdoc that does not address use described (quoting below):

On a related note I would like to make a case for <iframe sandbox> + SW combination that would allow embedded to control networking of the embedded document, where embedder and embedded document are from the same origin & without allow-same-origin. (maybe that's what srcdoc should do ?)

The use case being - Site wishes to load user uploaded content even if offline (think jsfiddle or dropbox). However site also doesn't trust uploaded content enough to share origin & storage / permissions shared across them.

Is this a good place to make a case for it ?

wanderview commented 5 years ago

Sorry, I misunderstood. I thought you meant an unsandboxed about:srcdoc iframe. Of course, the unsandboxed case would have to work before they could work in the sandboxed case with allow-same-origin.

Gozala commented 5 years ago

Sorry, I misunderstood. I thought you meant an unsandboxed about:srcdoc iframe. Of course, the unsandboxed case would have to work before they could work in the sandboxed case with allow-same-origin.

Got it! Indeed unsandboxed iframes to delegate to SW work in Firefox.

annevk commented 5 years ago

It seems weird to me that srcdoc with sandbox but without allow-same-origin can bypass the service worker. Do you recall why that was decided that way?

wanderview commented 5 years ago

Doesn't a srcdoc with sandbox but without allow-same-origin get an opaque origin?

annevk commented 5 years ago

It does.

wanderview commented 5 years ago

Then it must not be controlled by a service worker with a different origin. Its not so much a "bypass" as creating a context in a different origin.

annevk commented 5 years ago

Well, but it's one entirely controlled by the embedder. Why should the embedder not get to control the networking too?

wanderview commented 5 years ago

We have no precedent for a cross origin service worker. That would complicate a lot of security checks in implementations. I personally would be opposed to doing that. I guess we've never explicitly discussed that situation before.

Also, the embedder is still in control. They can simply not use the sandbox attribute. By using sandbox without allow-same-origin they are saying they don't trust the content of what they are going to be loading in that context and I don't think we should give it access to the service worker.

annevk commented 5 years ago

Oh right, I guess there are a bunch of subtleties I had not fully considered. I was only thinking about network requests (which would also be a different enough to maybe be a problem), but message access and such would indeed be bad.

Gozala commented 5 years ago

By using sandbox without allow-same-origin they are saying they don't trust the content of what they are going to be loading in that context and I don't think we should give it access to the service worker.

But it also implies that entrusted content can conspire with server endpoint. While with allow-same-origin it can effectively do whatever it's pleased to (assuming it's on same origin).

Oh right, I guess there are a bunch of subtleties I had not fully considered. I was only thinking about network requests (which would also be a different enough to maybe be a problem), but message access and such would indeed be bad.

That is a good point, in the use case I'm trying to outline embedded untrusted content should not have access to SW registration nor it should be able to exchange messages.

I know I'm repeating this, I appologize, what is the best way to make a case for this. Today there is no way for PWA to load untrusted content, not offline at least. There is also growing number of use cases in P2P space that would drastically benefit from a way to do so IPFS, Dat, SSB, webtorrent, blockstack, zeronet to enumerate few.

annevk commented 5 years ago

No worries, I suspect what's needed is

kevodwyer commented 4 years ago

Hi, I would similarly also like to indicate support for this feature.

We wish to be able to load arbitrary and untrusted html/css/js into a iframe. I want protection from spectre et. al. attacks and also from javascript execution escaping from the confines of the iframe. The limitation that it is not possible to intercept requests from an iframe if allow-same-origin sandbox is NOT set is a huge deal for us. The scenario is a E2E encrypted web application where html/css/js resources are decrypted locally. I then wish to display them inside a sandboxed iframe.

I have created a POC at: https://kevodwyer.github.io/sandbox/ Hopefully that explains the flow and the issue.

This behaviour has come up in discussions on various use cases in the following issues: VS code web view - 1437 web mail - 765

ianopolous commented 4 years ago

Have there been any more thoughts or development on this issue? Is there any way to help move this forward?

Gozala commented 4 years ago

One other alternative that came to my mind was to try and not shoehorn things onto sandboxed iframe but rather consider solution for loading sandboxed web applications with some networking capabilities. Which could possibly manifest something like:

<iframe sandbox srcworker="./service.js" />

Idea being that sandbox could load all of it's content by fetching it from service worker provided by ./service.js. That would allow embedder to fully control CSPs.

ianopolous commented 4 years ago

Indeed, for protection from spectre et al I'm told we should be using COOP and COEP as well as CSP sandbox - this way we are protected in browsers that don't have out-of-process-iframes as well. However that approach seems to suffer exactly the same problem as here, not being able to serve sub assets from a service worker for a unique origin.

The srcworker idea should work in that case too I believe if it is implemented.

dispeakble commented 3 years ago

Is there currently any solution to have a single service worker registered at the window level (top) and have access to the "fetch" events inside iframes (of any kind)? Or to put it another way: Why aren't the fetch events triggered for iframes without a src attribute?

I've tried using iframes without a src attribute but with no luck (including with sandbox="allow-same-origin allow-scripts"). The src attribute must be a real URL, meaning it needs either a SW interceptor or a real html page from the server. Blob URLs as well as srcdoc attributes don't contribute to the fetch event in the main service worker. Also the URL must be on the same domain for the fetch events to start working for iframes. One other thing to mention is if the parent script tries to open the iframe document to write something:

iframe.contentDocument.open(); iframe.contentDocument.write('hi mom'); iframe.contentDocument.close();

The fetch events will be ignored even if the src attribute is set with a valid URL.

wanderview commented 3 years ago

Why aren't the fetch events triggered for iframes without a src attribute?

You are running into implementation bugs. The parent service worker should be inherited for about:blank, srcdoc, and blob URL iframes. For example, the relevant chromium bug is:

https://crbug.com/880768

I think firefox is the only browser that does any inheritance of the service worker in these cases at the moment.

Rainmen-xia commented 2 years ago

One other alternative that came to my mind was to try and not shoehorn things onto sandboxed iframe but rather consider solution for loading sandboxed web applications with some networking capabilities. Which could possibly manifest something like:

<iframe sandbox srcworker="./service.js" />

Idea being that sandbox could load all of it's content by fetching it from service worker provided by ./service.js. That would allow embedder to fully control CSPs.

need this feature。

kettanaito commented 2 years ago

FWIW, I can't get the following setup work in either browser (Chrome 96.0.4664.55 / Firefox 94.0.2 ):

<iframe
  title="frame"
  srcDoc="<script>fetch('/resource').then(res => res.json()).then(console.log)</script>"
  sandbox="allow-same-origin allow-scripts"
></iframe>

<!-- register the worker here... -->
<script>
  navigator.serviceWorker.register('./sw.js')
</script>

The GET /user request is never propagated to the parent worker (the "fetch" event listener does not get called). I confirm that the worker registration is successful (this surfaces as a part of https://github.com/mswjs/msw/issues/1006, we've got the worker registration thoroughly tested).

@wanderview, given that you state this should function in Firefox, do you see any mistakes I'm doing with the setup above?

wanderview commented 2 years ago

The service worker needs to be controlling the page before you create the about:srcdoc iframe. That means both registered and controlling. So registered before the page loaded or the SW called clients.claim().

kettanaito commented 2 years ago

Thank you, @wanderview. So it may be a race condition between sw registration and creating an iframe. I will try that.

Yrobot commented 1 year ago

I create a demo which sw proxy the requests in Iframe, which may fit the sandbox feature. https://service-worker-demo-yrobot.vercel.app/ this is the demo repo: https://github.com/Yrobot/serviceWorker-demo