Why are Cloud Functions not stopped from writing when using Security rules in Firestore? - firebase

I'm using Cloud Firestore as my back-end. I'm using rules so only authenticated users can read some data (private data) and none of them can write. I have also created a function that is triggered when some new content is added to the database. However, when the function is triggered, I'm able to write data even if the rules as set to false.
How to stop that from happening?

Actually when you access to Firestore via a Cloud Function (using the Firebase Admin SDK) none of the security rules apply.
The following documentation https://firebase.google.com/docs/admin/setup explicitly indicates that for the Relatime Database:
The Admin SDK lets you interact with Firebase from privileged
environments to perform actions like Read and write Realtime Database
data with full admin privileges.
but it is the same with Firestore.
There is also a note in this Firestore "Get Started" documentation https://firebase.google.com/docs/firestore/security/get-started:
Note: The server client libraries bypass all Cloud Firestore Security
Rules...
As said above, this not only applies to the Admin SDK but also applies to the other server SDKs, because you use these server SDKs from what Firebase calls "a privileged environment", like your own server (under your control) or Cloud Functions (under your control too, since you are the only one able to deploy Cloud Functions code). See also What is a "trusted server environment" in Firebase?
If you want to restrict the write access for your Cloud Function, you will need to develop a specific business logic, in your Cloud Function, to mimic your security rules.

Related

Pass context value into firestore document add/set/update from Admin SDK

I am looking to use the https.onCall to accept some input from a user (such as data about another user). I'd then like to do some advanced processing on that data including retrieving sensitive data from other entries on my firestore that should not be exposed. Depending on the outcome of that analysis, I will update other locations in the database. However, I am concerned about the security of the original call and its source. I know that I have the context parameter on the onCall to verify the source was logged in, but I'd like to apply security rules to the final write based on the context.auth provided to the cloud function.
The security rules are straight forward for normal database operations but not if I'm doing an operation (seeded by a normal user) routed through the Admin SDK.
Thoughts?
but I'd like to apply security rules to the final write based on the context.auth provided to the cloud function
As you are aware that you can identify which user made a call to functions as well as that Admin SDK has super-access to database, the general flow should be to write functions in a way that they only edit documents that should be editable by the user.
If you had still like to narrow down access, you can do that for firebase database by passing databaseAuthVariableOverride when initializing admin app.
Read more on authenticating with limited privileges
When you use the admin SDK, or any of the server SDKs, it always bypasses all security rules. Rules only apply to access coming directly from web and mobile clients using the client SDKs.
If you need to apply some sort or restricts to data written from your backend, you will need to code that into the logic of your backend code. Security rules will be of no help.

Flutter/Firebase: Admin features in-app or cloud functions?

I'm writing an app with Flutter and Firebase (using both Firestore, Storage and Authentication so far).
Currently the app shows content from Firebase, but now I'm trying to figure out how the best way is to implement writing/editing/removing stuff in Firebase.
The goal is to have users with admin privileges.
My question is if I can build an Admin Panel inside the client app (which would be ideal), or if that's considered bad practice and I should build an Admin Panel in another app and using Cloud Functions.
For example, currently I perform Authentication (signup/register) in the Flutter/Dart code and when registering it creates a field in Firestore isAdmin = false, which I then can manually set to true (if I want) in the Firestore console. Could this somehow be an "unsafe" way of doing this?
The goal is to have users with admin privileges
Since you are using the Authentication service you already have half of the solution: with authentication you can identify each user who is using your app.
The other part is Authorization: this is normally done with Security Rules in Firebase, both for Firestore and Cloud Storage.
To be able to authorize certain users (identified through authentication) with Admin privileges, you need to know which users have the admin role in such a way you authorized them to execute the admin functions.
One possible way to identify the admin users is to have an isAdmin flag in some user documents in Firestore, as you mention in your question. There is an example of Firestore Security Rule using this approach in the documentation.
HOWEVER, you will encounter some problem if you want to use this flag (stored in Firestore) with Security Rules for Cloud Storage. At the time of writing, it is not possible to read the value of a Firestore document in Security Rules for Cloud Storage.
The solution is to use Custom Claims. You will find all the details in the doc on how to implement it in such a way it fulfill your needs.
Can I build an Admin Panel inside the client app?
Yes, you can very well do that. As soon as your security is correctly implemented (through Authentication and Security Rules, as explained above), there is nothing that prevents you to develop an Admin panel. If a user that is not admin can access the Admin panel, he/she will not be able to perform the admin actions (i.e. writing/editing/removing Firestore or Cloud Storage data).
Moreover, with Custom Claims, you can access them in the front-end to modify the client UI based on the user's role or access level (i.e. showing the pages, buttons and menu items of the Admin module only to admin users -note however that this does not prevent someone to reverse engineer your app and execute the queries dedicated to admin users: this is why it is key to correctly implement the Authentication and Security Rules parts-). See this section in the Custom Claims doc.
Should I build an Admin Panel in another app and using Cloud
Functions?
If you don't want to over-complexify your app with some logic to hide/show the Admin panel elements (based on Custom Claims, see above) you can very well build the Admin Panel in another app.
If you have specific needs/access restrictions that cannot be implemented through standard Security Rules you could very well use some Cloud Functions to check the user is an admin and to execute the writing/editing/removing admin actions (note however that while it is quite easy to interact with Firestore from a Cloud Function, it can be a bit more tricky with Storage: using the Cloud Storage Client SDKs is much easier than interacting with Cloud Storage through Cloud Functions).
You would preferably use Callable Cloud Functions, since "with callables, Firebase Authentication and FCM tokens, when available, are automatically included in requests". (See https://firebase.google.com/docs/functions/callable).
Side Note: You may be interested by this article, which details how to to create an Admin module for managing users access and roles. (Disclaimer: I'm the author).
the idea of ​​creating an admin panel for any flutter app
The idea is for two applications with different names and they will be linked to each other with Firebase
for more details see the video from the link
https://youtu.be/d7qoff-I8BU

How do I account for Google Cloud Firestore security rules in Firebase Functions?

If I create a Firebase Function, I am able to freely read and write to my Firestore database using:
const admin = require('firebase-admin');
[...]
admin.firestore().collection("collection").add({"foo": "bar"});
While I see that the firebase-functions library provides a reference to firestore, I can't see in the documentation how this is used in a similar manner to add/update data with the constraints of security rules.
Is this the the class I should be using, or are there other means to adopt this security from within a Function?
Code that uses backend SDKs, such as Firebase Admin, or any of the Google Cloud SDKs, always bypass security rules. This includes code running in Cloud Functions, which is considered "backend". You can't use security security rule to limit their access. Security rules only apply to access from the client SDKs, used along with Firebase Authentication.

Can cloud functions bypass firestore security rules

I recently developed with the implementation of firestore and firestore security rules.
Certain authenticated users can grab data if they are created by them, was one of the feature of the app.
i.e,
A creates X
B creates Y
A can't access Y and B can't access X.
This is ensured using security rules.
I deployed the app with cloud functions, and this acts as an api.
Simulating the security rules passes without failure, but when called the api for accessing via tool like postman,
A can access Y and X
and B can access X and Y.
I read this stack overflow question that talks about overwriting the security rule if used by firebase-admin sdk, which is what I am using.
But i am just curious, is there any other ways to restrict outside api tools to fetch data like this?
Here is the link
All access to Firebase and Cloud products (Realtime Database, Cloud Firestore, Cloud Functions) coming from any backend SDK will bypass security rules entirely. This includes the Firebase Admin SDK and any other Cloud SDKs. Security rules only apply to web and mobile client access.
YES, It Will
I enabled the following rule!
still, I was able to fetch data with
help of cloud function via Created API
/* The following code blocks whole database access*/
match /databases/{database}/documents{
match /{document=**}{
allow read, write:if false;
}}

Pass user auth to Firestore from Cloud functions

So I'm trying to build an http endpoint using a Cloud function. This cloud function is only invoked after the user signs in. So I can pass the user token and verify it on the server side. I understand how to do this.
I also have security rules on my Firestore collections with authorization rules set up using request.auth.uid. This also just works if I use the firebase web sdk.
But my question is - how do I use the same authorization rules via cloud functions? I don't want to rewrite my auth logic separately for the http endpoint.
Security rules only apply to access from web and mobile SDKs. It does not apply to code using any of the server SDKs, including the Firebase Admin SDK and anything you would use with Cloud Functions. You will have to apply your own logic to check the validity of data before it's added to Firestore. The same is true for Realtime Database and Cloud Storage security rules.
As you use the admin sdk in your functions, the check for the auth looks a bit different. Just watch this video from The Net Ninja. He is explaining how to do this. Just use the generated token instead what’s been used in the video.

Resources