samuelgozi/firebase-firestore-lite

It would be great to be able to override ENDPOINT

Closed this issue · 9 comments

I want to put firestore access behind Cloudflare, so I'll cname db.myapp.com to point to firestore.googleapis.com—to be honest I'm not sure this will work (I should have tried with the official library first tbh), but I think it should.

This way I can have some way to mitigate if someone tries to DDoS me (or since firebase is so scalable, more realistically this could be described as a "billing attack").

Oh I guess I can just set it manually after initializing the db. Derp sorry disregard

I wouldn't recommend that you do that, and its also not currently possible with my, or the official SDK.

The main reason that I don't recommend it is that the original firebase endpoint will still be accessible, so if someone wanted to DDoS you, it will be very easy for him to just find your projectId and DDoS the firebase endpoint directly.

As for why it's not possible with the SDKs, well, its because the endpoint is generated based on the API version that each library supports. So let's say that you do want to overwrite this, and you hardcode your endpoint in the library. What will happen when the library no longer supports the API endpoint that your domain points to? The library won't work, and it will be very hard to find the reason why.

I would suggest you contact the Firebase team and ask them for their opinion. If they do indeed recommend that you proxy their API I will kindly add this feature in a few hours.

I did ask in the google group but didn't really get any concrete answers. There is a host option in the official library but I'm not sure if it works / what it does. I did find this article also from the Reddit you posted in, though the author didn't really describe in technical detail what he did or how he did it 😕

I totally agree that someone smart could still figure out how to attack me by grabbing the projectId and directly querying firestore.googleapis.com but I figured this would at least make it slightly more cumbersome for the attacker.

I was also thinking I could combine this with CF Workers to completely hide the projectId (I could generate a secure random token and replace it in the worker with the real—secret—projectId) and this would also be somewhere where I could implement a caching layer for firestore at some point. It's likely a lot of my data won't change much; I anticipate it being read-heavy.

I'm probably over-thinking this! But considering I will definitely have publicly-readable data on my site, I would like some sort of lever to pull in case things get out of control.

I reopened this issue so that I remember to update you on any advancements. Adding this feature is very easy, however, making sure there are no side effects or bugs takes more time and there are no docs about this.

Things you should consider when doing this:

  1. Don't requests for very dynamic data.
  2. Check if limiting the query sizes in the security rules can satisfy your concerns.
  3. If you are only for DDoS attacks to "read" operations, note that the effectiveness of the attack won't be that great(millions of requests costs a few bucks).
  4. You need to hide any identifying info about the firebase project, which can be found in emails and SMS messages from firebase(for password resets, welcome messages, email link sign in etc) as well as any firestore response that includes a document or collection (document and collection names includes the projectId and database name, which will require you to manually check each response and manipulate it) as well as authorization endpoints and even some errors.
  5. This will only protect you from amateur attacks because someone with more knowledge can just open the dev tools and look for the info in step 4 that you forgot or missed.

My honest suggestion is to ask firebase what they recommend, and maybe send a feature request for a solution. I will send them an email to see what they have to say and update here.

My gut also says there's probably some benefit to putting firestore behind Cloudflare even just for dealing with organic spikes in traffic—I'm not entirely sure, just kinda guessing.

What do you mean by "don't request for very dynamic data"?

I don’t believe there will be any benefit to using cloudflare as proxy for Firestore for organic spikes in traffic. Firebase was designed from the ground up to deal with that.

Firestore is also protected by many “invisible” layers of google infrastructure by default. I’m talking about attacks level 4 and below, and it’s very optimized for speed.

Adding a proxy from an outside network will create bugs and a bottleneck for speed.

What you are concerned about is level 7 DoS attacks. They can be mitigated by using Google cloud armor, but I’m trying to figure out if it can be set up to work with Firestore(It might already be set in place).

And to answer your question, I meant that you should check if cloudflare caches requests, and if it does you should make sure that the cache invalidates often enough so that if you have a collection or document that updates often, it won’t be cached for too long.

Gotcha. OK I think I'm really over-thinking this. You should probably close this. I'd much much rather have time spent completing the API surface & more examples / docs. This is like the last thing I'd worry about. Thanks for discussing with me!! ❤️

If I don’t receive an answer I’ll close it. You are not overthinking it. It is a real problem that every app needs to tackle in one way or another. I just want to make sure that we know what the right solution is. If indeed there is no “built in” solution from google cloud then it might affect the library.

Update: I got no answer, but did some of my own research.
It might be possible to use a Google service called "cloud armor" which lets you fine-tune access to your cloud resources.

I also looked into the reference for the official SDK, and the host option is just for replacing literally the host. So you will still need to send some identifying information.

For those reasons and the reasons stated in the previous comments, I close this issue.
I might update if I stumble upon a better solution.