Insecure rules in firebase - google-cloud-firestore

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.

Related

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

Can't access Firestore after etting "allow all authenticated"

I'm initializing FireStore in my Chrome extension like they explain in the docs:
import { initializeApp } from "firebase/app";
initializeApp({apiKey:'...', ...});
Then I call setDoc to store a document. Everything is fine when I set allow read, write: true in the access rules. But when I change it to allow read, write: if request.auth != null, all my Firestore requests start failing with Error adding document: FirebaseError: [code=permission-denied]: Missing or insufficient permissions.
I assumed that providing my Firestore API key and other data in the initialization code would automatically make it authenticated. However, Firestore thinks that my requests are anonymous for some reason. How do I fix this?
Here's my config:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null
}
}
}
The request.auth check if the request is coming from authenticated user in firebase authentication.
The Firestore API key is only to send the request to the correct firebase project, but it doesn't make the request.auth != null.
You need to authenticate against firebase authentication in order to get request.auth != null. But in your case I beleive you don't want the users to authenticate, so you need some other security rule to get what you really want to check.

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...

Reading and writing in firestore only through cloud functions

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.

How strict Firestore Rules have to be?

Can I trust the data that are coming in the Firestore, or do I have to check everything and absolutely not trust the incoming data, because client can fake everything?
For example, can client fake uid, email and display name?
firebase.firestore().collection("users").doc(state.user.uid).collection("friendRequests").doc(payload.uid).set({
uid: payload.uid,
email: payload.email,
displayName: payload.displayName
});
Firestore rules:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read;
}
match /users/{userId} {
allow read, update, delete: if request.auth.uid == userId;
allow create: if request.auth.uid != null;
}
match /users/{userId}/friendRequests/{friendId} {
allow create: if userId == request.auth.uid
&& friendId != request.auth.uid
&& !exists(/databases/$(database)/documents/users/$(request.auth.uid)/friends/$(friendId))
&& !exists(/databases/$(database)/documents/users/$(request.auth.uid)/friendRequests/$(friendId))
&& !exists(/databases/$(database)/documents/users/$(friendId)/friends/$(request.auth.uid))
&& !exists(/databases/$(database)/documents/users/$(friendId)/friendRequests/$(request.auth.uid));
}
}
}
Set of rules is already quite big and I didn't even check yet if the data structure is valid and if friend uid exists.
The request.auth in your security rules is populated by Firebase Authentication. That means that the user triggering the rules must have signed in with Firebase Authentication, and that the profile in request.auth is belonging to the user that signed in.
The only way someone can hijack that process is if they get access to the administrative credentials for your project. With that they can generate any tokens they want. But if this happen, they can already access your database without restrictions, so the additional step of forging a token is rather useless.
Of course when using a social provider (Facebook, Github, Google, etc) users can set whatever display name they want. So you typically should not depend on that being valid, beyond using it to display a name for each user.