Rules in Firestore Firebase - firebase

I am setting the rules for my firestore database but I can't understand the meaning of malicious user . If I have the path:
/junction_user_item/PROVA/items/A23W4.... where A23W4.. is the uid . For this path I set the following rule:
match /junction_user_item/{multiSegment=**}/{userId}{
allow read: if request.auth != null
allow write: if request.auth != null
}
Each document of this path contains the value 'likes' (each time the document is displayed by any logged-in user, the value can be incremented by 1 if you like the picture:
likes:firebase.firestore.FieldValue.increment(1)
The idea is that under the path `/junction_user_item/PROVA/items/' there is a collection of photos and anyone can like it by editing the document.
Now, what can a malicious user who has logged in do? Can he use that path and increase the 'likes' property by as much as he wants of any document ? I can't put the rule :
allow read, write: if request.auth != null && request.auth.uid == userId
because the documents under that path must be accessible to everyone.
Also how to make sure no one can edit/delete the path?
/junction_user_item/PROVA

Related

Firestore rules not working like they should. Path and values are correct, but still saying invalid permissions on read

So I have these firestore rules here:
match /Customers/{customerId} {
allow read, update, create, delete: if request.auth != null && get(/databases/$(database)/documents/Users/$(request.auth.uid)).data.businessId in resource.data.businessIds || request.auth != null && request.auth.uid == resource.data.uid || request.auth != null && get(/databases/$(database)/documents/Users/$(request.auth.uid)).data.businessId == resource.data.businessId || request.auth != null && get(/databases/$(database)/documents/Users/$(request.auth.uid)).data.customerId == resource.data.customerId;
match /ServiceLocations/{ServiceLocationId} {
allow read, update, create, delete: request.auth != null && get(/databases/$(database)/documents/Users/$(request.auth.uid)).data.businessId == resource.data.businessId;
}
}
And for some reason when I am calling read on /ServiceLocations/{ServiceLocationId} inside the /Customers/{customerId} hierarchy I am getting invalid permissions. But I am confused because the path and values are correct. I am able to read the customerId document fine so there is no issue there, but specifically I cant read the serviceLocationId documents which is a document inside the ServiceLocations subcollection inside the customerId document.
get(/databases/$(database)/documents/Users/$(request.auth.uid)).data.businessId
is a valid path which returns a businessId.
resource.data.businessId
and businessId is a valid field inside the serviceLocationId document and both values do infact equal eachother. Yet it is still returning false.
Attached are two images showing the "Users" document of the user I am sending the request from which includes the businessId field, and the serviceLocationId document I am trying to read from, which also includes the businessId field. And as you can see both values do infact match and the paths are correct.
https://i.stack.imgur.com/vJNPN.png
https://i.stack.imgur.com/W8sgM.png
Here is an example of one of the requests being called invalid:
db.collection("Customers")
.doc(selectedCustomerData.customerId)
.collection("ServiceLocations")
.onSnapshot((snapshot) => {
Am I just doing something wrong? It makes no sense to me. Any help would be appreciated.
I suspect this is a case where the security rules cannot filter your data for you.
Specifically, I think the rules may not be able to enforce this requirement on their own:
get(/databases/$(database)/documents/Users/$(request.auth.uid)).data.businessId ==
resource.data.businessId;
Try passing a filter in the query where you also pass the user's business ID (.where('businessId', '==', 'The business ID of the user')), or pass the business ID as a custom claim rather then looking it up in a document.

How to add a Firebase security rule for checking if logged in users email is in a list

I try to add a security rule that should grant write access given that the logged in user is in a list within the record.
I.e. my "tournament" record has a List officials in where I put the emails of those that should be able to alter the tournament.
I don't get this to work so I guess that my rule has some error in it.
match /tournaments {
allow read: if request.auth.uid != null;
allow write: if request.auth.token.email in resource.data['officials'];
}
The rule you have written is has some missing syntax. The rule must be like mentioned below:
match /tournaments/{tournamentID} {
allow read: if request.auth.uid != null;
allow write: if request.auth.token.email in resource.data['officials'];
}
The /tournaments/{tournamentID} indicates that the rule will apply for all documents present in tournament collection and {doc_id} is a wild card to representing documents in that collection.

Limiting permissions to the author not working in Firestore rules

I am attempting to move my Firebase rules from testing where every user could read and write every document to one where only the author can update or delete documents they create.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if request.auth != null;
allow update, delete: if request.auth != null && request.auth.uid == resource.data.author_uid;
allow create: if request.auth != null;
}
}
}
This set of rules is resulting in a 'Missing or insufficient permissions" error at Firebase init and if I attempt to delete a document. If I go with my original rules then everything works.
allow read, create: if request.auth != null
I do a standard firebase.initializeApp (but dont want to publish my keys here - lets just say the same initialize works with the basic rules and on three other firebase projects I have). The delete call is as follows and works with the simpler rule set as well but not the tighter rules above:
const decrement = firebase.firestore.FieldValue.increment(-1);
firestore.collection('story').doc(storyid).delete().then(function() {
firestore.collection('users').doc(getUserID()).update({
saves: decrement
});
})
(thank to Sam Stern on the FB team for guidance)
First, there was a mistake in the rules description. While request.auth.uid is defined by firebase the resource.data.author_id needs to be defined by the developer on each of their documents. In this case the 'story' document contains a 'creator' property that is the userid of the owner. So the correct variable would be resource.data.creator in the above rules.
In addition its possible to define the documentid as the userid, as is often the case when you are creating a 'user' object for each account in your firebase app. In this case the userId is the same as the documentId so the following rule would control update permissions that only allow the owner of that document to change it.
match /users/{userId} {
// In this scope the "userId" variable is equal to the documentId because of the wildcard declaration {userId}
allow update: if request.auth.uid == userId;
}

Restricting access to Firebase Firestore and Storage

I'm using Firebase exclusively in my app - Auth, Firestore, Functions and Storage.
Within Firestore, my data is structured as below:
/users/<user_id>/<user_data>
/listings/<listing_id>/<listing_data>
<listing_data> contains a user_id field.
Within Storage, my data is structured as below:
/images/<user_id>/<image_id>/<images>
I have the following scenario:
A user must only be able to access their listings
A user must only be able to download their files
A user can can share their name from their <user_data> with selected users
A user can share selected images with selected users
I have no ideas how I can go about this. At the moment, anyone can access anything if they're authenticated, so I guess the first step is to lock this down, and then some how assign rights?
I thought about adding an access list object, and then writing middleware to check this, but it doesn't feel like the correct way
You have to modify the rules of firestore as:
service cloud.firestore {
match /databases/{database}/documents {
// Restaurants:
// - Authenticated user can read
// - Authenticated user can create/update (for demo)
// - Validate updates
// - Deletes are not allowed
match /restaurants/{restaurantId} {
allow read, create: if request.auth.uid != null;
allow update: if request.auth.uid != null
&& request.resource.data.name == resource.data.name
allow delete: if false;
// Ratings:
// - Authenticated user can read
// - Authenticated user can create if userId matches
// - Deletes and updates are not allowed
match /ratings/{ratingId} {
allow read: if request.auth.uid != null;
allow create: if request.auth.uid != null
&& request.resource.data.userId == request.auth.uid;
allow update, delete: if false;
}
}
}
}
The root of my database is restaurants.You have to replace those parameters with that of yours.

Configuring rules for Firestore so user only gets records they own

This is a followup to this question
Firestore permissions
I'm trying to set rules on my firestore
service cloud.firestore {
match /databases/{database}/documents {
match /analysis/{analysis} {
allow read, write: if request.auth.uid == resource.data.owner_uid;
}
}
}
My goal is
a. When doing a list operation only those documents belonging to a user are returned
b. only documents a user owns can be read or written by that user.
With the above configuration b. is accomplished.
how do I do accomplish a. ?
Remember that firestore rules are not filters, they're a server-side validation of your queries.
You should always make your queries match your rules, or else you'll get permission errors.
In your case you already made the rule to enforce reading/listing on user owned documents. Now you simply have to make the corresponding query with the right filters :
const userId = firebase.auth().currentUser.uid
db.collection("analysis").where("owner_uid", "==", userId)
Another thing.
With your current rules, your users won't be able to create a new document, only edit an existing one, here are the updated rules to allow that :
allow read: if request.auth.uid == resource.data.owner_uid;
allow write: if request.auth.uid == resource.data.owner_uid
|| request.auth.uid == request.resource.data.owner_uid;

Resources