Firestore Security Rule: Check user input on get query - firebase

I'm creating a blog with Firestore. I have two collections called users and blogPosts. Each document in blogPosts contains name, createdAt, createdBy and password (plain string) field.
I want to create a security rule so clients can access a document only if they provide the correct document password.
According to an idea in this link, I wrote a rule like this:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /blogPosts/{postUid} {
allow write: if
request.resource.data.createdBy == request.auth.uid &&
request.resource.data.name is string &&
request.resource.data.name.size() > 2 &&
request.resource.data.name.size() < 32 &&
request.resource.data.password is string &&
request.resource.data.password.size() > 5 &&
request.resource.data.password.size() < 32
allow read: if
request.auth != null &&
request.resource.data.password == resource.data.password // <---- THIS LINE IS NOT WORKING
}
}
}
I get this error in playground with the rule above: Error: simulator.rules line [16], column [8]. Property resource is undefined on object. So it means we don't have resource.data on read queries.
How can I achieve my goal with Firebase security rules, so only clients that has blogPosts password can access to documents?

What you're trying to do isn't possible with security rules (and also isn't really "secure" at all). A client app can't simply pass along some password in a query. The only time input is checked is for document fields in a write operation, not document reads.
If you want to check a password, you will have to make some sort of API endpoint and require that the caller provide the password to that endpoint. Again, bear in mind that this is only as secure as your ability to keep that password a secret, because once it becomes known (perhaps by simply reverse engineering your app), anyone will be able to use it.

Related

Firebase how check path contains value and allow read and write other path

At the moment i try to build a chat in flutter with google firebase.
Now i would like my database more secure.
That means only users (room_3) in chat can read and write data data.
Is it possible to check a path contains a user value
and if the user value is contains allow read a other path?
Here my database structer:
/chat/product_id/product_id_12345/chat_room_id/room_1/message_1/message2...
My idea is i add in 'room_1' the user id.
Then i check the user is contains in 'room_1'.
If the user is contains i allow read and write data the complete path (message_1/message_2...).
Here my example:
If you have any questions fell free to ask me.
Many thx.
In the security rules for the messages subcollection you can read the parent document and check whether the current user is in the user_id field with:
...
match /messages/{message} {
allow read:
if request.auth != null &&
request.auth.uid in
get(/databases/$(database)/documents/chat_room/$(chat_room_id)).data.user_id
}

Firebase database security rule, check auth.email in resource.data

Error [firebase.firestore] FirebaseError: Missing or insufficient permissions.
I have an object that a few users are allowed to update. An admin will set their email, and these users who sign in with those email will be allowed to update.
These are the rules that I have tried:
allow update: if request.resource.data.managerEmails.val().contains(request.auth.email) && request.resource.data.id == resource.data.id;
allow update: if request.resource.data.managerEmails.contains(request.auth.email) && request.resource.data.id == resource.data.id;
allow update: if request.resource.data.managerEmails.includes(request.auth.email) && request.resource.data.id == resource.data.id;
The resource to update:
{
id: "someid",
...fields,
managerEmails: "abcde#email.com,anothermanager#email.com",
}
User auth who is updating:
{
uid: "rSTLnYD9aisyZJHQPC6sg7mlsZh1",
email: "abcde#email.com",
...
}
Update:
Using request.auth.uid has been working in other rules, but in this case, I have to use emails because the users might not have signed up yet.
Using Rules Playground, I get Property email is undefined on object. Maybe using request.auth.email is not possible?
I was having the same problem but switched from using firebase.auth.email to firebase.auth.token.email and it now works.
I strongly suggest doing two things.
Firstly, store UIDs instead of email addresses. A UID is the preferred way to identify a single Firebase Auth account and is always guaranteed to exist and be unique. Email addresses are not.
Secondly, store the list of users as an array type field instead of comma separated string. This will be much easier to manage overall.
After you do these two things, the rule becomes simple:
allow update: if resource.data.managerUids.hasAny([request.auth.uid]);
use: request.auth.token.email insted request.auth.email
documentation here

Firstore database rule 'request.auth.uid' not working

Can someone help to solve why this firestore rule is not working. Am I missing something simple ??
If you look at the clip below you see my rule for /users/{userId} is allow read: if request.auth.uid == userId; BUT THE SIMULATION FAILS , and my chrome console also confirms "Missing or insufficient permissions"
You can't use wildcards for document locations like that in the simulator. Your "Location" string on the left should identify a single document.
Also, if you want to test authentication, you will need to provide a UID to test with in the "Firebase UID" field.
In your case, you will want to test using the same UID string value in both the document location and the UID fields.

Firebase rules: Create if collection id does not exist

What I am trying to do is create a firebase rule that will allow create operations if an id does not exist in allow create. To be specific, I am using firestore, not the firebase real time db. I am really new to firebase, but have done some research before posting here. Most of the examples I see are around auth.
Consider the follow data structure. The name of the collection is called flags
US - //(This is the document ID. Not auto generated
- country: United Stages
- name: US
- colors: [red, white, blue]
UK -
- country: United Kingdom
- name: UK
- colors: [red, white, blue]
What I am trying to do write a rule, IF name in the posted data does not match an existing document ID. The reason why I opted to set my own document ID is because of this article
My current rule is:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
allow read: if isLoggedIn();
allow create: if ! exists(/databases/$(database)/documents/flags/$(inComing().name))
// functions
function isLoggedIn() {
return request.auth != null
}
function inComing() {
return request.resource.data
}
}
}
But when I try posting some data with a non existent document id, I am getting an access denied error. I am logged into the app so I know it is not failing on the first part of the rule.
In summary, my questions are:
How can i check if a document ID exists based on the posted datas name key?
So what i am try is allow create: if ! exists(/databases/$(database)/documents/flags/$(inComing().name)). In the simulator, I am using create, and setting the path to flags/US. The payload is:
{"__name__":"/databases/(default)/documents/flags/US","id":"US","data":{"name":"US"}}
If I run the simulator, i get access denied which is expected. But if i change the path to flags/CA or change the payload to {"name":"CA"}, which does not exist, I am getting getting an access denied.

Firestore Security Rules: If timestamp (FieldValue.serverTimestamp) equals now

How do I check if user on client sided created document with only firebase.firestore.FieldValue.serverTimestamp()?
I have following:
allow create: if request.resource.data.timestamp == ??
What should I have instead of ??. I have tried serverTimestamp() firebase.firestore.FieldValue.serverTimestamp(), now or now() but it doesn't work.
It is possible to do it in Firebase like this:
".validate": "newData.child('timestamp').val() === now"
I am looking for the same solution. Any ideas? Thanks
You can access the current request timestamp in Security Rules using the request.time attribute (docs), which is the Firestore equivalent to the Realtime Databases's now. You'll therefore want something like:
allow create: if request.resource.data.timestamp == request.time;
For serverTimestamp() this should evaluate to true.
You should always validate client input in Security Rules, even if you're using serverTimestamp(). Security Rules doesn't automatically know the server input the value instead of the client, so without this check, a malicious client could create a different created at time.

Resources