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.
Related
I am setting up my app so that any client device can only impact collections/sub-collections that they own. However, to interact with other users, a user will need to make the app create a row in another user's collection. What is the safest way to do this?
My idea for this would be to have the app call a cloud function to create the record in the other user's collection. The cloud function would read the request and make sure of the following:
The incoming request has an existing UID
The incoming request's user's email is verified
The incoming request's UID has a record in the Firestore 'users' collection
If I do this, is this just as secure as using Firestore security rules?
The question you're asking is unfortunately not as easy to answer as you expect. Firestore security rules don't ensure general "security" of your app any more than backend code. Rules let you specify rules for reads and writes according to the conditions you provide, if you want to use them. If rules are not sufficient for the requirements at hand, then maybe backend code will work better. In either case, you can allow or deny access based on conditions you provide.
In terms of functionality, both options allow you to allow or restrict access in different ways. Neither one is more or less "secure" than the other. The main issue you should consider is which one lets you most easily specify those rules. Security rules are fundamentally more limited in what you can check, while backend code is fundamentally more flexible. The option you choose is dependent on what you're trying to allow or reject.
The constraints you specified in the question could be enforced by either security rules or backend code, so I don't see that one is necessarily more or less secure than the other.
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.
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.
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.
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;
}
}
}