Firestore rules 'Simulated read allowed' but fails in browser - javascript

My security rules are super simple. I have two collections - riders and races:
riders: can only be read from or written to when the user is signed in
races: can be read from by unauthenticated user; written to when user is signed in.
service cloud.firestore {
match /databases/{database}/documents {
// restrict read/write on all to authenticated
match /{document=**} {
allow read, write: if request.auth != null;
// then allow collection read if match
match /races/{id} {
allow read, list: if true;
}
}
}
}
These rules allow what appears to be the correct setup using the Firebase consoles Rules Playground but in the browser auth users behave as expected but the unauthed users are returned an error when making a call for a race:
core.js:6456 ERROR FirebaseError: Missing or insufficient permissions.
at new e (prebuilt-47338342-439a2133.js:188)
at prebuilt-47338342-439a2133.js:10415
at prebuilt-47338342-439a2133.js:10416
at e.onMessage (prebuilt-47338342-439a2133.js:10438)
at prebuilt-47338342-439a2133.js:10355
at prebuilt-47338342-439a2133.js:10386
at prebuilt-47338342-439a2133.js:15146
at ZoneDelegate.invoke (zone.js:372)
at Zone.run (zone.js:134)
at zone.js:1276
// service call
this.racesCollection = this.firestore.collection<Race>('races');
this.racesCollection
.doc(id)
.valueChanges()
.pipe(takeUntil(this.destroy$))
.subscribe((response: any) => {
console.log('=== APP SERVICE emits race ===', response);
this.race.next(response);
});
I've tried rewriting the rules but cannot seem to find my way around this one. Any help or ideas appreciated! Thanks.

You should write your security rules in such a way they overlap:
service cloud.firestore {
match /databases/{database}/documents {
// restrict read/write on all to authenticated
match /{document=**} {
allow read, write: if request.auth != null;
}
// then allow read for the races collection for all users
match /races/{id} {
allow read, list: if true;
}
}
}
In addition, note that list is a "sub-case" of read, so you might remove the list rule, i.e. just do allow read: if true;.
BTW, the simulator does correctly show that your rules do not allow reading a document in the races collection if you are not authenticated.

Related

Firestore security rules - trouble with permission to write to a collection

I've attempted to set up a security rule where a person writing a document to a particular collection may only do so if their uid matches the uid contained in the document, but can't get it to work. In this case I am writing a document to a collection called 'embedUsers' and the document being written contains a uid field that was acquired when the user account was created.
The rules are set up as follows:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /embedUsers/{documents=**} {
allow read: if true;
allow write: if resource.data.uid == request.auth.uid;
}
}
}
The document is written by an Angular client, using the following code:
const userRef: AngularFirestoreDocument<UserModel> = this.afs.doc(`embedUsers/${user.accountAddress}`);
console.log("current logged in user", this.fireUser.uid);
try {
console.log(user.uid);
await userRef.set(user, { merge: true });
} catch (e) {
console.error(`FireAuthService.updateUserData unexpected failure with error ${e.message}`)
throw new Error("updateUserData failed");
}
console.log("wrote embed user successfully")
Although I have checked that the uid of the signed in user matches the uid field in the data object being written, this call to userRef.set fails with FireAuthService.updateUserData unexpected failure with error Missing or insufficient permissions. It seems like something must be wrong with my rules but I'm not sure what (if I change the rule to simply say allow write: if true; the document gets written as expected.
As explained in the doc, "When writing data ... the request.resource variable contains the future state of the document". So you should adapt your rule to:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /embedUsers/{documents=**} {
allow read: if true;
allow write: if request.resource.data.uid == request.auth.uid;
}
}
}

Can a user update the script in a console and access other users' data in my firebase code?

For context, I display my Firebase app's configuration in the app.js file (is this safe?) and in order to give a user their data I list the following code:
db.collection('whispers').where("sender", "array-contains",
userID).orderBy('time').onSnapshot(snapshot => {
let changes = snapshot.docChanges();
changes.forEach(change => {
renderSay(change.doc);
});
});
Could a user remove the 'where' condition and access all data in this collection? I only use anonymous sign in so nothing special required in accessing their own data besides using the same device and not clearing data.
I doubt that could be possible by reverse-engineering but the actual security lies in the security rules.
You can change them from the Firebase Console
Here is a video from Firebase and here is the documentation
service cloud.firestore {
match /databases/{database}/documents {
// Match any document in the 'users' collection
match /users/{userID} {
allow read: if request.auth.uid === userID;
allow write: if request.auth.uid === userID;
}
}
}
Using the above security rules will allow users to read and write their data ONLY.
So even if they reverse-engineer your code, it will harm their data only and other data will be safe.
For more details please check the links above and you will get familiar with wildcard [{userID} in this case]
PS: Only you or anyone with access to your Firebase Console can change the rules
EDIT: This Medium Article has many types of rules explained. Please have a read there too :D

NativeFirebaseError: [storage/unauthorized] User is not authorized to perform the desired action

I'm having problems uploading an image to Firebase Storage. I'm using React Native's #react-native-firebase/storage and the installation and connectivity seem to be fine because I'm able to reference images just fine:
const ref = firebase.storage().ref('myImage.png');
The problem is definitely permissions based because when I temporarily remove:
: if request.auth != null
from Firebase console Storage Rules:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
This worked just fine:
firebase.storage()
.ref('images/test.jpg')
.putFile(myImage[0].path)
.then((successCb) => {
console.log('successCb');
console.log(successCb);
})
.catch((failureCb) => {
console.log('failureCb');
console.log(failureCb);
});
So how do I authenticate to use putFile securely?
EDIT:
I'm using "#react-native-firebase/storage": "^6.2.0"
Thanks in advance!
Edit Firebase storage rules to allow uploads without the need of installing #react-native-firebase/auth.
Navigate to Firebase console
In Sidebar under Develop open Storage
Open Rules tab
replace below rule
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write
}
}
}
And Publish
Done
That's it Frank!
I wrongly thought of the app as a user that was already authenticated through the GoogleService-Info.plist file and not that the user of the app needs to be authenticated.
My steps to fix:
install #react-native-firebase/auth
go into the Authentication section of your firebase console and Enabling the Anonymous Signin method
call firebase.auth().signInAnonymously() in componentDidMount()
And...finally able submit the putFile to storage successfully!
Big thanks #FrankvanPuffelen !!
I'm new in coding, but i face same problem.
In my Situation, It did not work with Ananymous SignIn.
I had to change the Directory location to make it work.
Original Rule:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o { => Change here
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
Change to:
rules_version = '2';
service firebase.storage {
match /b/Your_APP_Name.appspot.com/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
we can over come this in two ways. either we need to authenticate the user while uploading the files to the database. or if it is only for the testing purpose i recommend to go to storage in firebase and click on rules and change "allow read, write: if request.auth != null" to "allow read, write: if request.auth == null". i recommend to autheticate the user for safe and secure files.
I hope your problem solved.

Firestore returns insufficient permissions, even tough it shouldn't

I have the following rules set up for my Firestore database:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /collections/{document=**} {
allow read;
allow write: if isAdmin();
}
match /general/{document=**} {
allow read;
allow write: if isAdmin();
}
match /inquiries/{document=**} {
allow write;
allow read: if isAdmin();
}
match /orders/{document=**} {
allow write;
allow read: if isAdmin() || resource.data.userID == request.auth.uid;
}
match /products/{document=**} {
allow read;
allow write: if isAdmin();
}
match /users/{userId} {
allow write, read: if belongsTo(userId);
}
function belongsTo(userId) {
return request.auth.uid == userId
}
function isAdmin() {
return resource.data.admin == true;
}
}
}
As you can see, everybody is allowed to read /products and its documents plus subcollections. Which works for the products, but somehow the product's subcollection (every product has one called collection-colors) can't be read.
FirebaseError: Missing or insufficient permissions.
Code causing the error:
retrieveCollectionColors(name) {
this.db.collectionGroup('collection-colors', ref => ref.where('product', '==', name))
.valueChanges().subscribe( (val: []) => {
this.collectionColors.next(val);
}, error => {
console.log(error);
});
}
The rules you have right now don't apply at all to collection group queries. You'll need to write a special rule for that. From the documentation:
Secure and query documents based on collection groups
In your security rules, you must explicitly allow collection group
queries by writing a rule for the collection group:
Make sure rules_version = '2'; is the first line of your ruleset. Collection group queries require the new recursive wildcard {name=**}
behavior of security rules version 2.
Write a rule for you collection group using match /{path=**}/[COLLECTION_ID]/{doc}.
So, if you want to allow collection group queries for "collection-colors", it will look something like this:
match /{path=**}/collection-colors/{doc} {
allow read: ...
}
This will apply to all subcollections with the given name. You can't selectively allow or disallow subcollections based on the name of the parent collection.

Keep getting missing permission when trying to add to user only

I am trying to allow read/write to only a users UID, however script keeps saying missing permission please help.
Many thanks`
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, update, delete: if request.auth.uid == userId;
allow create: if request.auth.uid == userId;
}
}
}
db.collection('users').doc(userId).collection('details').add(...
The rules you've written only match documents that are immediately within the collection called "users". However, you're trying to access a document within a subcollection of a document of under "users".
The documentation addresses this situation very specifically, so be sure to read and understand how hierarchical data works for security rules.
If you want to apply per-user rules to all documents in a collection, and all the documents in all nested subcollections under that document, you can simply say this:
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read: if request.auth.uid == userId;
match /{document=**} {
allow read: if request.auth.uid == userId;
}
}
}
}
Note that the match has to be nested like this in order it to use the userId wildcard from the outer match.
Probably your forgot to enable sign-in provider in the firebase console.

Categories