Firebase rules security warning - firebase

I'm getting the following message in Firebase:
The Cloud Firestore "(default)" database of your project contains
rules that are not secure.
But I have the rules as the documentation says and I don't see any other option. What I want is that anyone can read, but just logged in users can edit content.
These are my rules:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if true;
allow read, write: if request.auth.uid != null;
}
}
}

With these rules any authentication user can write all documents in your database, including overwriting documents that were created by other. You're also allowing everyone (no matter if they're authenticated) to read all data in the database, which seem much broader than most apps need. While these are close to some of the default rules you can start with, it is typically not enough for a production app, which is why you receive the warning.
You'll typically want to further lock down access to the database. For example, you might want to ensure that users can only write documents that contain their own UID in a specific field. That way you'll always know who created a document, and can use that to control access to that document.
If you are certain this is the minimum data access that your app requires to function, you can disable the warning emails in the Firebase console. But as said before, in my experience this type of access seems much broader than what I typically see in well functioning, and well protected, apps.

Related

exposing firebase credentials with user information

hey i am developing a web application for a public project using firebase and I am worried about exposing user emails.
The basic idea of the website is:
1.) input -> user provides email and some information
2.) calculations happen on the server and information is written to firestore (admin sdk)
3.) output -> user receives a link in their email to view the results
the information i store is essentially
taskID {
input,
email,
output
}
users only have read permissions
my firebase rules as follows:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if true;
allow write: if false;
}
}
}
i know the firebase credentials are somewhat exposed on the client, so I am worried that somebody can use them to list all tasks, then iterate over all tasks to get the emails and the user provided inputs.
Is this possible at all? Would i have to have a different collection which can only be read by admins, then reference the fields?
taskID {
input,
email : privateCollectionID,
output
}
privateCollectionID {
email
}
Thanks
Your current rules allow anyone and everyone to read all data in your database at will.
If that's not what you want, you'll need to structure your data in a way that meets what you do want.
If you want some data to be publicly readable, and other data to be only readable by the owner of that data, you will need to separate that data into different documents/collections and apply different rules to them.
For an example, have a look at the Firebase documentation for public/private access in security rules.
You could use a Callable Cloud Function that you call from the front-end passing the desired email.
The CF queries the collection to find the document corresponding to the email and returns the document data.
Since the Admin SDK bypasses security rules you can deny read access to this collection in the security rules.
Note that:
This will not prevent users to test for a certain email existence but it will prevent them getting direct (one shot) access to the entire emails list.
The response time will be a bit longer compare to a direct query to Firestore via the JS SDK. More details in this article.

Are firestore rules case sensitive or does my path contain an error?

I am new to firestore rules and I encountered a glaring problem.
My rules look like this:
If I uncomment either or both the sections, and comment the part with (document=**), all project calls to the firestore realtime database will fail because of permissions. I cannot figure out why. In all documentation this is the preferred way. Is it case sensitive? I know it is not the auth part that fails, because if I leave the rules like in the image, all project calls work.
For clarity, this is what the database structure looks like (yes, Projects has a capital P):
Are Firestore rules case sensitive?
Yes, the collection/document IDs are case sensitive.
match /{document=**} {
allow read, write: if request.auth != null;
}
The above rule allows any user logged in with Firebase authentication to read and write to any collection in the database. If you still get permission errors, check if the user is logged in or no.

Secure Firestore database using rules. Check authentication. Is it enough?

I'm new to Firebase and trying to understand database rules. I'm using Firestore.
I have a database that basically needs to be read by all users, and also write. All users can see the documents in the database, and with certain actions they change certain fields. In certain cases they will detele certain old expired documents.
Now, I understand that I cannot leave read and write open to all, since this is not secure. So I am using authentication, I will anonymously authenticate the users, so that only authenticated users have access.
I understand this does the job:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth.uid != null;
}
}
}
Now, my question is, is this enough? I'm not a hacker, so I don't exacly know how a hacker would or could hack and detele/change stuff in my database, but does this mean that only changes can be made to the database through using the app? Could someone still hack this if they aren't using the app, and authenticate in some other illegal way.
Thanks so much for the help, I've tried to read to get to the bottom of this, but haven't managed.
Firebase security rules can't limit access to a single app. All of the APIs are all available for public use for anyone who has an internet connection. They are all documented right here: https://firebase.google.com/docs/reference/rest/auth
The purpose of Firebase Authentication is to make sure that individual users have their individual access controlled appropriately. As soon as you let users create accounts using anonymous or email auth, they will have full access to all documents in the database with these rules. So, what you have right now is not really "secure" by most definitions of that word. You will have to decide if this is "secure" enough for your purposes.
You are also likely to get an email from Firebase saying that your rules are insecure. It's not a good idea to use /{document=**} like this, which matches all documents, which might not be what you intend. Minimally, you should call out the individual collections that you want users to access instead of using this global wildcard.
Does this mean that only changes can be made to the database through
using the app?
Anyone that can get your Firebase config elements could write a simple HTML page using the JavaScript SDK and try to interact with your Firestore backend. Note that it is not difficult to get your Firebase config elements, see at the bottom for more details.
This is why it is of upmost importance to implement a set of security rules if you want to protect your data.
Now, it is important to note the following point about Firebase Authentication and “registered“ users:
You should note that anyone can “create a new user in your Firebase project by calling the createUserWithEmailAndPassword() method or by signing in a user for the first time using a federated identity provider, such as Google Sign-In or Facebook Login” (if these identity providers are activated, of course). See the doc.
So, again, with your Firebase config elements, someone can easily build an HTML page that calls the createUserWithEmailAndPassword() method.
This means that if you want to limit the access of your app to some specific users just by using allow read, write: if request.auth.uid != null in your Firestore security rules, it is not sufficient.
One possible approach is to use Custom Claims. You can for example, set a specific claim to all your authorized users (e.g. authorized = true) and adapt your security rules to check the existence of this claim in the user token.
Note: How to find the Firebase config elements of a web app?
It is not really difficult to find the Firebase config object. Just look in all the HTML or JS files composing the app for the apiKey string.

Trying to make app secure with API key, but it isn't being used

I've created a web application that displays data from my cloud firestore. I'm about to release it to the public, but I don't want just anyone to be able to read/write to my database.
I have currently restricted my API key to only allow requests from my website's url, but it doesn't seem to be doing anything. I've even deleted it from the app entirely and it is still able to access the database.
Is there a rule I need to set up in my firestore to make it require an API key? I've googled plenty of things, but all I can find are articles on why it's ok to have your key be available to the public.
It's not possible to restrict access to Firestore based on some plaintext API key or web site domain. If you're publishing an app that provides direct access to Cloud Firestore (or Cloud Storage, or Realtime Database), the only way to secure it is with a combination of Firebase Authentication and security rules. The security rules allow you to express who can read and write which collections and document.
If you aren't using Firebase Authentication, and your default security rules allow universal read/write access, then anyone with an internet connection will be able to read and write every document.
A slight variation on Doug's excellent answer is to allow all users to write to specific documents that pre-exist and that have impossible to guess names. These document names then essentially become your own API keys, that you share (out of band) with the users of your app.
The security rules for this can be as simple as:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow create: if false;
allow update: if exists(resource['__name__']);
allow get: if true;
allow list: if false;
}
}
}
So: anyone can get/update any existing document that they know the name of, but they can't create a document, nor get a list of all documents.
This prevents the need for using Firebase Authentication. On the other hand it means you can't lock down access on a per user basis. Any user that somehow gets access to the document name, can now read/write it at will.

Firebase Cloud Firestore restrict user access (Banking Application)

I am working on a banking app using firebase cloud firestore. I have already set the rules like so:
// Allow read/write access on all documents to any user signed in to the application
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth.uid != null;
}
}
}
My database is structured like this:
/consumers/{consumer_id}/transactions/{transaction_id}
the {consumer_id} will contain the account balance for that consumer along with other details and the {transaction_id} will contain the details about each transaction.
So if any authenticated user wanted to say, withdraw money they can do so using the android app/Web app. The problem is, can that same user access the database (eg: update their account balance) using their credentials with the REST endpoints without my knowledge? If so how do I prevent them from doing so?
There is no way to limit access to Firestore to just users who are using your app. Anyone who has the configuration data for your Firebase project, can call the APIs in that project. And as soon as you publish your app, you're sharing the configuration data with those users. So you'll have to assume that some malicious user(s) will at some point call APIs on your project without using your app.
For this reason you should enforce all business rules that you have in a trusted environment, such as your development machine, a server you control, Cloud Functions, or... server-side security rules. Since no user can access any of these, even if they run their own code, they'll be forced to adhere to your business rules.
Some examples:
Each transaction document probably contains the UID of the user who is posting that transaction, and of course users should only be able to post transactions with their own UID. You can enforce this in security rules with something like:
match /databases/{database}/documents {
match /consumers/{consumer_id}/transactions/{transaction_id}/ {
allow write: if request.resource.data.posted_by == request.auth.uid;
}
}
So now anyone (no matter if they're using your app or not) can only post transactions if that document contains their own UID. You'll probably want to verify a bit more, such as whether there is even a account document for them, and maybe whether you've verified their account in some way. All of these can typically be done from server-side security rules.
For more on this, see the documentation on accessing other documents in security rules, the pro-series video on building secure apps, and this video on security rules.
Since you keep the balance of each account in their parent document under /consumers/{consumer_id}, you'll need to update that document whenever a transaction is posted under it. While this is possible from within security rules, it's going to be quite involved. It's going to be easier to perform this update of the balance in server-side code.
A good solution for this is to run the code that updates the balance as a Cloud Function that gets triggered whenever a transaction is created (and/or updated if you allow that). Since this code runs in a trusted environment, you can be sure only you can modify it, and thus it can safely update the balance for the new/modified transaction.

Resources