Add a limit for data reads firebase firestore - firebase

We have an iOS app that uses Firestore. The app only reads data (no writes), we have no user accounts and nothing on the database must be protected. For that reason we ran with these naive security rules
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read;
}
}
}
However, Firebase has warned us (sure, for good reasons) that this puts us at risk for two reasons:
Any user can read anything from the database, therefor nothing is secure.
I don't see this as a problem because we have nothing that must be kept secret. At least for now, sure, that might change.
Unlimited reads are permitted
This is were the problem lies. I suppose a malicious user could read our database millions of times and thereby shut us down or simply force us to pay a large bill (we use the Blaze plan, pay as you go).
How can we protect us from this? I've seen similar questions here but they don't provide any helpful suggestions, How to limit rate of data reads from Firebase?
My idea is that we could use anonymous user accounts in the app and then in our security rules only allow read if user is "logged in" (thereby anyone using the app). I'm far from an expert on Firebase and security issues, but wouldn't this at least make it harder or impossible, for someone to read our database millions of times because it must be done through the app?
Any other suggestions how we may approach this?

There's not really a way to throttle the read rate for a particular client app once you allow read access to a document. With fully public read rules, everyone on the internet could read documents repeatedly to run up a bill. The chances of that happening are really slim though, and you should report what appears to be abusive behavior to Firebase support.
You can get rid of the warning message by calling out the individual top-level collection you would like the clients to be able to read. Since Firebase doesn't know which collections you might want to allow or disallow access to, you should be explicit. For example, something like this for each collection:
match /collection1/{document=**} {
allow read;
}
match /collection2/{document=**} {
allow read;
}
If you do this, be sure to remove the rule you have now that allows access to all documents.

If it's just read only operation then you can consider using remote config, as remote config is completely free.
But if it's necessary to use firestore database for your scenario, then consider Firebase Anonymous sign-in and setting the following security rule
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /collection_name/{documentId} {
allow read: if request.auth.uid != null;
allow write: if false;
}
}
}

Related

Fixing '[Firebase] Your Cloud Firestore database has insecure rules'

After finishing development for my application, I realised that I had left the insecure rules on as it was my first major project with Firestore and I had to fix some issues and I changed the rules to allow me to use it. When I went to turn it off, the whole application stopped working as it only accesses it through these rules. I have read a lot of responses here and am aware this question has been asked many times before but I am truly stuck and have no idea how to proceed.
Currently there is no signup required as it is on a shopify app - store owners must be signed in to use it and so the database has an area such as /users/ where each entry is the store name and holds it's associated data (so people do not need accounts to use it). There is also an exterior portal on Retool that edits all of these records on the database - I believe this complicates things as I feel like two sets of rules are required.
My current rules:
// Allow read/write access to all users under any conditions
// Warning: **NEVER** use this rule set in production; it allows
// anyone to overwrite your entire database.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
I am now aware that store owners could wipe or steal the data of other shop owners and so far have set up daily backups, but haven't been able to fix this issue. I would like to know if it is possible for me to set the database up in such a way that allows store owners to still read/write to their sections but also the people using the Retool portal that interacts with db to have access.
I have no idea how to proceed and any help would be sincerely appreciated. I saw something saying about limiting users to using an extra layer of server's REST api but have no idea how I would go about implementing this and if I would have to change rules.

Firebase API in JavaScript and therefore public, concern for Auth?

I appreciate that variants of this have been posted before, however I am not seeing one that directly hits this concern. The Firebase recommendation is that for Web interfaces the JS includes enough information for the client side JS to identify the application in question. This config can be used for all the activities that are needed. In my case :
createUserWithEmailAndPassword / signInWithEmailAndPassword / sendEmailVerification
Basically this means that anybody can simply start creating users for my application. They can also sign-in, which means any data rules I have that, an example like below, are now open to the world for updates.
service cloud.firestore {
match /databases/{database}/documents {
function isSignedIn() {
return request.auth != null;
}
match /clubs/{club}
{
allow write: if isSignedIn();
allow read: if true;
}
}
Here is what I have done. I have added a Role to the User list, and the User list is not writeable by anybody except my back-end processes which bypass the rules.
Therefore although malicious people could create accounts and sign-in, they could never give themselves the most vital Roles. It still leaves me with 2 issues, firstly it just does not feel quite right :-), secondly how do I know which accounts are valid people trying to sign-up for my application and which are bogus. Those that are valid need their Role updating in the back-end. Right now when I have like 5 users of my app it is ok (haha), but how do people manage this in a more voluminous application?
I appreciate you taking the time to read this and I appreciate any thoughts and / or suggestion you might have.
if you need more granular control around your roles, you can check custom claims
Also, there are a few posts around which tell you a few patterns, take a look:
Controlling Data Access Using Firebase Auth Custom Claims
Patterns for security with Firebase: supercharged custom claims with Firestore and Cloud Functions
there's enough information there to get you started.

Firestore public collection rules

I have a web app that is basically a list of public items, non authenticated users can search the database and list the search results from the collection. Until I started getting daily emails from Firebase about "insecure rules in my Firestore database", I thought everything was OK, but now I am doubting them.
Here are my rules:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if true;
allow write: if request.auth.uid !=null;
}
}
}
I am new to Firebase/Firestore and trying to understand:
1- The data is meant to be public but getting emails from Firebase, are these rules actually an issue?
2- Although the data is meant to be public, it would suck if someone would just drop by and download entire collection in one go. Thus, is possible to restrict public access a little by somehow preventing access to the collections/documents unless the request comes from the web app/domain? Maybe some form of token? Or some other approach?
Right now, your rules allows public read access to all documents in your database, as well as write access to all documents to authenticated users. Firebase generally considers that insecure.
The global, recursive /{document=**} wildcard is kind of dangerous since it might apply to data that you didn't intend to be readable or writably. You should instead call out the specific names of the collections in individual rules. That way, if you create new collections, they will not be automatically included with the wildcard.
In general, your rules should be as specific as possible and not depend on a global recursive wildcard.

Cloud Firestore rules - Allowing anybody to update one specific field in a document

I'm working on a PoC (Proof of Concept) application that users can download wallpapers to their device. All of the data is served using Cloud Firestore & Storage.
There is NO LOGIN for this application. Anybody can download the application, and immediately download the wallpapers she or he desires.
Bearing that in mind... I would like to have a counter that tracks how many times each specific wallpaper was downloaded.
While I have it "working" - I am questioning the rules I have set up in Firebase..
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read;
allow write: if request.auth != null;
allow update: if request.resource.data.counter is number;
}
}
}
My thought process with the rules above:
Anybody can read.
Only authenticated users can write. (I am managing all of the data with a headless CMS; Flamelink; so the 1 and only authenticated user is myself.)
Update the counter if the data is a number..
It's that last rule that I am questioning.
Is this a safe method of security to deploy to production?
Again - no login for this application, users can download all of the wallpapers with no authentication, and there will be a counter next to each wallpaper for users to see how many times each wallpaper has been downloaded.
The rules are not "secure" by any normal definition of that word. Here's what they allow. Anyone with an internet connection who knows the name of the project (which is easy to get) can:
Query for any document in the database
Update any existing document with any numeric value for counter in any document (it doesn't even have to increment, or be a positive integer)
On top of that, anyone who is able to get their Firebase Auth ID token (again, not terribly difficult for determined attacker), can fully create and write any document in the database. If you say there is no Auth at all in your app, then this is not really an issue, but if your project is configured to allow any form of authentication, it would be possible for an attacker to start writing anything.
You will get email from Firebase saying that your rules are not secure, mostly because you're allowing everyone to read everything.
What you should do is define more specifically what your security requirements are, then translate those into rules that actually meet those requirements. If you want to allow unauthenticated write access to your database of any kind, you are in a bit of trouble, as there is no way to make sure that the access actually matches the download behavior you're trying to measure. You'll be better off counting the downloads in whatever process manages the download, which is probably going to require a more sophisticated backend than what you have now.
But if allowing public read/write access is indeed what you want to allow, you'll be better off by making your rules more specific. For example, you can limit which collection the anonymous user can write to, and making sure they can only ever increment the counter, if these are the things you want.

Do firestore security rules provide access to documents by default?

I am trying to write security rules for my Firestore-based app and I am confused as to whether access to documents/collections in Firestore is the default (meaning that I need to write rules to specifically forbid access to any documents in the cases where I should limit access) or if access to documents is not the default (meaning that I need to write rules to specifically allow access in the cases where I want to enable access)?
From the firestore documentation I read this:
Every database request from a Cloud Firestore mobile/web client library is evaluated against your security rules before reading or writing any data. If the rules deny access to any of the specified document paths, the entire request fails.
From this, it seems that all documents are accessible by default but I am not certain and wanted to ask.
Any clarification would be greatly appreciated! 😅
Access is denied if not explicitly granted by any rule. That means that collections that are not matched by any explicitly declared path or wild-card pattern will not be accessible.
The first match statement is the mandatory /databases/{database}/ pattern and syntactically you must declare at least 1 allow statement within the match clause. So by default, a locked database will look like this
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}
Because omitting the if false would grant access to everything.
When you start declaring specific rules for collections, you will implicitly deny access to collections and path patterns that are not explicitly granted access.
The easiest way to confirm that is to test it with the built in rules simulator in Firebase console.
You can test this for yourself pretty easily in the console simulator. Adjust the rules so that only a certain collection is protected in some way, then try to simulate any access anywhere else at all. All reads and writes will be rejected.
You have to allow access to a document at some point in order for a mobile client to access it. Once you do that, you can not reject access to that document on any other condition for any other rule for the same access.
So the general rule is: a user can't access anything by default, but once they have any rule that allows access, it can not be rejected again by some other rule.

Resources