Reading and writing in firestore only through cloud functions - google-cloud-firestore

I want to set my Cloud Firestore database permissions so that no one will be able to read and write from it except through Cloud Functions.
How can I do this?
My guess (according with Firestore docs) is that I have to set the right condition for what I want, but what condition would it be? I don't know how to "communicate" the cloud function call with the rules.
service cloud.firestore {
match /databases/{database}/documents {
match /<some_path>/ {
allow read, write: if <some_condition>;
}
}
}

Simply eliminate all the rules and replace them with a rule that rejects everything:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}
With nothing explicitly allowing mobile and web client access, none will be allowed. The server SDKs always bypass security rules, so as long as the service account that you use to initialize the SDK has write access, it will work. The default service account used in Cloud Functions should be fine.

Related

firestore.get function not working in Cloud Storage security rules

I want to investigate that the user is admin or not but this is not working.
I get an error:
You don't have a permission to acces the object
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /articles/{allPaths=**} {
allow read;
allow create: if firestore.get(/databases/{database}/documents/users/$(request.auth.uid)).data.isAdmin == true;
allow update;
}
}
}
I try to rewrite the code, but this is not working too:
allow create: if firestore.get(/databases/{database}/documents/users/$(request.auth.uid)).isAdmin == true;
According to this Firebase blog Security Rules in Cloud Storage for Firebase now supports cross-service Rules with two brand new functions firestore.get() and firestore.exists(). Your rule should be
allow create: if firestore.get(/databases/(default)/documents/users/$(request.auth.uid)).data.isAdmin == true;
instead of
allow create: if firestore.get(/databases/{database}/documents/users/$(request.auth.uid)).data.isAdmin == true;
This feature allows you to read only the Firestore data belonging to the same Firebase project as your Cloud Storage; you will not be able to query Firestore data from a different project.
Firebase currently supports only 1 database instance per project so the name must be (default) in path. A similar answer explains this.
I have also recreated the issue at my end and it turns out this feature is only available to (default) databases.

User can't write to Firestore database even though he is authorized

I created a rule in Cloud Firestore to read/write based on wether the user is signed in through Firebase Auth or not.
From my understanding based on what I read in the official documentation, the following code should allow the signed in user the correspodent permissions to the userID document inside the data collection.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/document {
match/data/{userId}{
allow read, write: if isSignedIn();
}
}
function isSignedIn(){
return request.auth != null;
}
}
Database image:
The idea is that after the user logs in, the code I wrote should verify if there is a document called ReservedID in data/userID/ReservedID, and if there isn't, create one for him, however, this collection is never created.
It does work if I remove the security rules.
Image of the error that shows in Android Studio:
However, after signing in using mAuth.signInWithEmailAndPassword, the user still can't write or read from the database. The Android Studio Logcat provides this message:
PERMISSION_DENIED: Missing or insufficient permissions.
Did I misunderstood how to properly set these rules in my database? Or could it have something to do with the code itself?
It looks like there are some issues with the code.
The match statement should specify the path to the collection and whole documents, rather than just one document. i.e you are using the path for single document match /databases/{database}/document instead of below path:
match /databases/{database}/documents {
match/data/{userId}{
}
With the above changes, the code will look like this:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match/data/{userId}{
allow read, write: if isSignedIn();
}
}
function isSignedIn() {
return request.auth != null;
}
}
You can verify this on playground

Insecure rules in firebase

I understand it's not good to set your read and writes to all users on Firebase;
But what if you leave your reads to all and your writes to only authenticated users?
What is the worst thing that could happen?
Is it easy for someone to gain access to the firebase project?
I'm currently using cloud firestore.
Sorry if this seems a little dumb, I'm new to this:
Thanks,
Jacob
EDIT: Current Rules:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if true;
allow write: if request.auth != null;
}
}
}
I've worked with Firebase for a long time and I've come to realize that the rules are a very good way to prevent unauthorized access to your data, by any third party - especially when used in tandem with rules set within your Application (be it Web, iOS or Android).
Personally, I usually set my rules to the following:
service cloud.firestore {
match /databases/{database}/documents { match /{document=**} {
allow read, write: if request.auth != null;
}
This means that only logged in users are allowed to access the data and write data as well.
If, instead, you want users to access the data without being logged in but only write data if they're logged in, then I would suggest these rules:
service cloud.firestore {
match /databases/{database}/documents { match /{document=**} {
allow read;
allow write: if request.auth != null;
}
In terms of how easy it is to access a Firestore Database when not authorized to:
Google has done a good job at keeping things secure.
Setting up these rules and some other checks within your Application is enough to keep things secure.

can't read path variable in firestore rules

I have some rules like:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /teams/{teamId} {
allow read, write, delete, list:
if debug(teamId) in debug(request.auth.token.teams)
allow create:
if true;
}
}
}
I am using claims to control access. Each user has an array of teams in their token. That part is working fine.
Basically, teamId (coming from the path) doesn't exist. Nothing is printed in the log for this variable. I can't figure out whats going on. Is there some different way to access that teamId variable?
by doing some logs, it seems that for accessing /teams/teamXXXX I'm getting multiple rule hits. First on /database/default/documents/teams and then again on /database/default/documents/teams/teamXXX The first rule pass is failing because {teamId} is not defined on that path. I need to somehow allow access to the collection while limiting access to the child documents
It looks like the way I'm accessing teams may be causing a problem. I'm getting teams by doing a query like:
instance.collection("teams").where('owners',
arrayContains: FirebaseAuth.instance.currentUser!.uid);
This must be triggering the rule check where no {teamId} in the path. I thought about wrapping my match statement like:
match /teams/{document=**}
allow read:
if (request.auth.uid != "")
match /teams/{teamId} {
allow read, write, delete, list:
if debug(teamId) in debug(request.auth.token.teams)
allow create:
if true;
}
}
I'm worried that this will just allow all documents. I'm stuck.
answering my own question.
When doing a search / list on a collection, it still matches the rule of /teams/{teamId} even though you are not specifically querying by teamId.
Meaning a search like instance.collections("teams").where(...) will still match /teams/{teamId}
In the match, {teamId} will be blank. Instead, you must look at the input paramters coming in via the "resource" variable. The items you have in the "where" clauses will appear in the resource variable. You must use the resource data to resolve your rules.
So I had to separate the "list" rule form the rest of the rules.

Basic Cloud Firestore security rules setup

I am currently using this default code to secure my Cloud Firestore database:
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth.uid != null;
}
}
}
This code works fine and the simulation is fine.
I tried to update the code and use the new default code I find in every guide:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth.uid != null;
}
}
}
But this code fails every time, the access is not granted.
In the simulation, I just try to read a document in a Collection named "parameters".
Am I missing something here? My plan is to harden the security access afterwards.
Ok my bad, I actually realised that the database access rules and the storage access rules have their own and separate security panels.
I was trying to update the storage rules with the default database rules...