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

Service workers and mixed content #493

Closed
annevk opened this issue Sep 27, 2014 · 16 comments
Closed

Service workers and mixed content #493

annevk opened this issue Sep 27, 2014 · 16 comments

Comments

@annevk
Copy link
Member

annevk commented Sep 27, 2014

Would default() allow mixed content while fetch() forbids it? Or should default() disallow it too?

@mikewest

@mikewest
Copy link
Member

mikewest commented Oct 2, 2014

@slightlyoff @jakearchibald and I had a conversation about this a week or two ago. I think Jake was going to write something up?

@jakearchibald
Copy link
Contributor

Fetch should return an opaque response for mix content, then elements can accept/reject based on their rules. Eg, would work but cause a mix padlock.

This allows something like a podcast app to be built without proxying heavy audio files through your own https server. Unfortunately we're a long way from podcasts being served over https :(

@annevk
Copy link
Member Author

annevk commented Oct 2, 2014

Wait, we would allow fetch() to get to non-TLS URLs too? o_O

Why are podcasts suddenly a problem? YouTube has TLS. Cloudflare makes it cheap.

@jakearchibald
Copy link
Contributor

Yeah, but the processor of the data gets to decide whether it reads the data or not.

A podcasting app would need to download and play content from around the web. If we can't do that we're crippling ourselves compared to native.

Proxying the RSS feeds seems like a small deal, but proxying 100mb files... not so much.

@annevk
Copy link
Member Author

annevk commented Oct 2, 2014

Are @briansmith and others game with this plan? It seems bad to poke holes.

@mikewest
Copy link
Member

mikewest commented Oct 2, 2014

Hrm. I recall a different conclusion. @slightlyoff noted that it's odd for a <video>, <audio>, or <IMG> tag to request an insecure resource, but the Service Worker can't do the same.

I suggested that when fetching in response to a page's request, we should pass through the request context and frame type in order to do the mixed content check.

@annevk
Copy link
Member Author

annevk commented Oct 2, 2014

Yeah, that would make it work for default(), but not fetch(). However, that those elements can fetch non-authenticated content is a bug and Firefox Nightly already shows a broken lock for it.

@jakearchibald
Copy link
Contributor

Thinking about this following a chat on IRC.

fetch('http://...', {mode: 'no-cors'}) should fail from clients without a direct link to a single window (so, fails in SharedWorker and ServiceWorker).

An empty serviceworker shouldn't change the behaviour of mixed content.

The question is do we want to support the "podcast" app case?

fetch('http://...', {mode: 'no-cors'}) from a window could succeed & show a mixed content warning unless "block-all-mixed-content" is set in CSP. The resolved value would be opaque.

To support this in a service worker we'd need a way to link the request to the client, which could be event.default() or similar, or something like windowClient.fetch(). This means we know where to show the warning, or fail if it cannot be shown. (added bonus: the request can be aborted if the client goes away)

If we can't build a podcast app today on the web, we're definitely losing something to native, but maybe the mixed content warning means we're losing there anyway. Perhaps it's not worth it.

@jakearchibald
Copy link
Contributor

CSP defines how SW handles mixed content and I LIKE IT.

@tolu
Copy link

tolu commented Aug 17, 2017

Sorry to bust in so late in this discussion but the fact is that I'm building a podcast pwa (available for disfunctional testing at https://tolu.github.io/podspace) and I've just spent a day trying to figure out how to solve this problem.
The app is very much WIP and I don't even have a well defined caching strategy so the service worker simply caches everything that comes through.
The only separation in logic is serving application files "network first" and everything else "cache first"(where requests for iTunes images fail, not to mention mp3's).

@jakearchibald if you have the time, could you please elaborate on how CSP can be used for avoiding this issue, or point me in the right direction. I would be eternally greatful!

I've looked around and tried some approaches but I fear I don't really understand how CSP should be used for a case like this.

@annevk
Copy link
Member Author

annevk commented Aug 17, 2017

@tolu there's no solution. Nobody implemented service worker mixed content exceptions and that feature has since been dropped. Everything needs to be HTTPS.

I know that's not great, but mixed content would not have been great either as it would decrease trust in your application. And as long as you can't actually get to the bits of the pod you can't display chapter information and such, which would make the experience a bit subpar.

@tolu
Copy link

tolu commented Aug 17, 2017

Thanks for the quick response, really appreciate it!

Then I guess that the only solution is having a proxy since I cant control the availability of https on resources from the iTunes API or the podcast file providers 😢

@grkblood13
Copy link

grkblood13 commented Sep 24, 2018

@tolu Did you ever find a solution to your problem other than using a proxy? I'm handling video so if you think proxying podcast audio is bad then you can imagine my concerns :)

@tolu
Copy link

tolu commented Sep 24, 2018

@grkblood13 actually I found out (this summer) that you are allowed (at least in Chrome) to add anonymous HTTP-requests to the cache 😄 (⚠️)

The issue remains that you CANT know if the data is a-ok or not however since there is no programmatic access to the response 😢
But for my case, just a private podcast player - the issue of risk / stability is fine...

The reason this is a big issue for audio is that there are SO MANY podcast providers out there that do not provide CORS headers or HTTPS (and a proxy would just prove to costly).

I was wondering why you would have this issue though?
From where are you fetching video (what services)?
Are you streaming (hls, hds, dash, etc) or using progressive download (mp4)?

// example using workbox
workbox.routing.registerRoute(
  ({url}: {url: URL}) => {
    // Return true if the route should match
    const isMp3 = /\.(?:mp3)$/.test(url.pathname);
	// define some own query param to figure out if this is
	// a regular request or if this should be cached...
    const offline = /podspace-offline/.test(url.search);

    return isMp3 && offline;
  },
  workbox.strategies.cacheFirst({
    cacheName: 'audio',
    plugins: [
      new workbox.expiration.Plugin({
        maxEntries: 60,
        maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
      }),
      new workbox.cacheableResponse.Plugin({
        statuses: [0, 200]
      }),
    ],
  })
);

// in another file, trigger cache by fetching resource like so
// request with no-cors since that is what audio-element does
const src = 'some-mp3-url';
await fetch(src + "?podspace-offline", { mode: "no-cors" });

// then you need to wait some time or do interval checking on cache like so
async function isItReadyYet(src) {
	const mp3Cache = await caches.open("audio");
	const keys = await mp3Cache.keys();
	return keys.map((r) => r.url).find((cacheUrl) => cacheUrl.includes(src));
}

@grkblood13
Copy link

The use-case for me would be private HLS streams, none of which i've seen being hosted via https. I've created a web-player that I would like to host using https, but of course those non-ssl sources won't allow them to play, and instead spit out mixed-content error messages. Proxying is not a option for me since that's outside the scope of a player and too costly as you mentioned. I looked into serviceworkers after watching a demo video on it's client-side proxying capabilities only to learn at the end serviceworkers are only supported via https. I might have to give what you mentioned a shot though. I also found a post that suggested setting the CSP content header to "upgrade-insecure-requests". Apparently that will take a http source and attempt to convert is to https, then if it fails it'll accept the original http feed. That would by far be the simplist method as it would illiminate the need for a serviceworker entirely.

@tolu
Copy link

tolu commented Sep 26, 2018

At least HLS ensures that CORS must be in place, at least if cross browser web playback with things like hls.js has been taken into account, which is a good thing!

The HTTPS part on the other part is tricky if you have no control over the servers...
Best of luck!

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

6 participants