Skip to content

External script intermittently loaded and causes CSP failure which breaks our app #187

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

Closed
JoshBoehm opened this issue Oct 6, 2017 · 10 comments
Assignees

Comments

@JoshBoehm
Copy link

Describe your environment

  • Operating System version: Windows 10 x64
  • Firebase SDK version: 4.4.0
  • Firebase Product: Auth + Realtime Database + Storage

Describe the problem

An external script is sometimes loaded (example: https://cyphme.firebaseio.com/.lp?start=t&ser=50153600&cb=11&v=5) which will break loading our application when the script is blocked (intentionally) due to our CSP.

My best guess so far is that it is only loading this script and breaking when it’s resorting to long polling instead of websockets.

Steps to reproduce:

Inconsistent: load https://cyph.ws in chrome -- maybe force long polling?

@JoshBoehm JoshBoehm changed the title External script intermittently loaded and causes CSP failure External script intermittently loaded and causes CSP failure which breaks our app Oct 6, 2017
@mikelehen
Copy link
Contributor

Could you clarify what environment you're using the SDK from? Since you have a CSP I'm assuming it's not a plain webpage.

FWIW- We have some exclusions to disable long-polling here:

If we're missing a case that's breaking you, a PR would be welcome. :-)

In the meantime, you could work around the issue by setting your databaseUrl to "wss://cyphme.firebaseio.com/" instead of "https://cyphme.firebaseio.com/" to force the SDK to avoid long-polling. But I'd prefer an SDK fix if possible. Thanks!

@buu700
Copy link

buu700 commented Oct 7, 2017

Thanks for the quick response @mikelehen! This is a plain web page that @JoshBoehm was referring to (https://cyph.ws). Anyway, we'll go ahead and test these solutions and see which one works best for us.

More generally, do you know of a good way to prevent Firebase from loading any external scripts at run-time? We have nothing against long-polling in and of itself (and would prefer that it be used when necessary, as opposed to just failing completely), but it would make our lives a lot easier if Firebase never tried to load external scripts or expected such attempts to work. (As another example, I know that in some versions of Safari the Auth module will try to load https://apis.google.com/js/client.js.)

@mikelehen
Copy link
Contributor

I'm afraid not. Can you explain more about your CSP and what your use case is? The Firebase SDK targets a number of runtime environments (browsers, chrome extensions, react native, etc.), but it sounds like you're trying to do something a bit different. Can you explain more? Thanks!

@buu700
Copy link

buu700 commented Oct 8, 2017

Hmm, well, that would be my #1 feature request in that case. Two related questions:

  1. Is there a way to support long polling without depending on an external script? As mentioned, I would prefer to keep this fallback option since there's no inherent reason we shouldn't be able to use it.

  2. Are external scripts ever loaded this way from other environments like Node and React Native, or just the browser?

    • The current behavior is acceptable for now in browsers, since every browser we support supports CSP, but we're also working on a NativeScript app (using the Node SDK), where this issue could be a blocker to releasing since NativeScript doesn't support CSP as far as I know.

As far as our use case: right now just a web app, with additional security requirements imposed by our application's threat model such that loading remote scripts at run-time (even over TLS) would be considered a high-severity vulnerability. (See first bullet here for more information.)

@mikelehen
Copy link
Contributor

  1. Unfortunately not. To be clear, these aren't exactly "external scripts" that are being loaded. The entire long-polling protocol is based on adding dynamic <script> tags to the page that then get dynamically-generated responses from the backend. This is designed as a lowest-common-denominator that works on even old browsers that don't support XHRs with CORS, etc. There are other ways to do WebSocket fallbacks that don't use <script> tags, but adding another mechanism is outside the scope of the Firebase Realtime Database SDK. So if our implementation violates your requirements, you'll have to just stick to WebSockets. As a sidenote, the recently released Cloud Firestore beta uses a different transport that is 100% XHR-based. So if this ended up being a sticking point for your use case, you could give it a try as well.

  2. Per the code I linked in my first reply, we disable long-polling on both Node.JS and React Native. I'm not sure about the rest of the Firebase SDK, but in general I would expect they don't dynamically load scripts on Node.JS / React Native as this isn't directly supported in those environments AFAIK.

Out of curiosity, have you considered adding exclusions to your CSP for Firebase-provided content since you're already trusting Firebase code in your app? For instance, if you excluded *.firebaseio.com I believe that would enable our long-polling transport to work.

@buu700
Copy link

buu700 commented Oct 8, 2017

  1. Ahh, got it. In that case, any idea why that would've been happening for us in multiple instances of Chrome 61 (on Windows 10 and Android 7)? Are the only two supported methods WebSockets and <script>-based long polling, or are there some methods in between that might've been skipped over for some reason?

  2. Perfect, thanks!

Out of curiosity, have you considered adding exclusions to your CSP for Firebase-provided content since you're already trusting Firebase code in your app? For instance, if you excluded *.firebaseio.com I believe that would enable our long-polling transport to work.

We're trusting the Firebase since it's open source (well, mostly open source and in the process of being fully open sourced) and can be publicly reviewed and audited, but that's a little different from downloading and executing unverified payloads at run-time. Our CSP actually doesn't even allow fetching scripts from our own servers (which would also be a high-severity vulnerability for the same reason mentioned above).

@mikelehen
Copy link
Contributor

Ahh, I see. Yeah, adding exclusions probably doesn't make sense in your case. :-)

Long-Polling and WebSockets are the only supported transports. The choice of which transport to use is a bit complicated, but if I recall correctly it works something like:

  1. Absent any prior knowledge, assume WebSockets works and try that.
  2. If it fails for any reason (even a network glitch or you refreshing the page before it is able to succeed), the next attempt will use long-polling. We actually set a "websocket_failed" flag in localStorage when we make our WebSocket attempt, and then clear it on success, so it's easy to get into this state due to transient failures.
  3. If on page load that "websocket_failed" flag exists, we'll use Long-Polling.
  4. If Long-Polling succeeds, we'll try to "upgrade" to WebSockets.
  5. If that works, we'll clear the "websocket_failed" flag so the next attempt prefers WebSockets again.

So it's possible you are accidentally getting into the "websocket_failed" mode and stuck trying to use Long-Polling until it succeeds (which will be never because of your CSP). So the only way to have reliable connectivity is to force websockets, which you can do via the wss:// trick I mentioned in my first reply.

@buu700
Copy link

buu700 commented Oct 8, 2017

Got it. Sounds like wss:// is definitely the way to go then, and while a configuration flag to explicitly guarantee that external scripts won't be loaded would be ideal, we shouldn't have any problems for now. Thanks for all the help!

@schmidt-sebastian
Copy link
Contributor

Closing this issue as per the comments above. @buu700, please let us know if the suggested solution doesn't work for you.

@buu700
Copy link

buu700 commented Oct 18, 2017

Seems to be working perfectly. Thanks!

@firebase firebase locked and limited conversation to collaborators Oct 26, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants