Firestore security rule get vs. list - firebase

Suppose I'm trying to make a webpage readable only when the user has the exact link to it, could I achieve this using a combination of the document ID and security rules as follows?
eg. I have documents stored at
/posts/{postID}
I have security rules set up:
match /posts/{postID} {
  allow get, write: if true;
  allow list: if false;
}
Would simply disabling the "list" operation make it such that you can only access a document if you already know its exact ID? It looks like the case to me but I'm not sure if I'm missing any edge cases.

Would simply disabling the "list" operation make it such that you can
only access a document if you already know its exact ID?
Yes, this is right.
Any query to the posts collection will return a "Missing or insufficient permissions" error, even a query that queries with the exact ID, like:
firebase
.firestore()
.collection('posts')
.where('__name__', '==', 'exactID')
.get()

Related

Firestore security rule that only allows empty documents

I'm basically trying to use a firestore collection as a an email list. Anyone can create a document that has their email as the id and nothing more. The tricky part is the "and nothing more" bit. When no data is provided in the request, request.resource is undefined which you can't check for in security rules to my knowledge. Is this possible? Or is it necessary to have something like one mandatory field for this use case?
Having empty documents regularly leads to issues down the line. Why not require a single marker field, and validate that in rules?
request.resource.data.keys.hasOnly("marker")
For the benefit of others looking to make an email list in firestore, this is the full rule I ended up using:
match /email-list/{email} {
allow get: if true;
allow list: if false;
allow create: if request.resource.data.keys().hasOnly(["marker"])
&& request.resource.data.marker == true
}

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.

Unable to base security rule condition on resource data in Firebase

I am attempting very simple thing and that is matching request.auth.uid to a field value in my transaction documents (like this resource.data.useruid) in Firebase security rule in order to get transactions of a particular logged in user. However, I don't get any documents while querying for them and get an error instead.
This is how the collection looks like - just one document there with useruid field.
The field's value is mapped to the users uid (screenshot taken in the Authentication -> Users tab.
And the rule looks like this
I should get the one document back but every time I query the documents with that user logged in (I am using angularfire2 for those purposes) I get Error: Missing or insufficient permissions.
If I modify the rule condition to return always true or if I only check for truthiness of request.auth.uid I get the query result alright. The funny thing though is that with resource.data involved - eg. checking for value of the amount field in the firebase rule - the condition is never met. I tried to write it like
allow read, write: if resource.data.amount == 3
and got the error again. Seems like I don't get the resource.data Map at all.
I feel like I am missing something obvious, although after reading the guides, it seems alright to me and I am already out of ideas. The debugging capabilities (or lack of) make the whole process very slow.
Could you please explain to me, why I don't get the resource.data Map in the firebase security rule or point me to a place where the problem might be?
You have most probably missed one specific point in the doc: your query fails "because it does not include the same constraints as your security rules". See https://firebase.google.com/docs/firestore/security/rules-query#secure_and_query_documents_based_on_authuid
The following, with your security rules works perfectly:
firebase.auth().signInWithEmailAndPassword("xxxx#xxxx.com", "xxxxx")
.then(function (info) {
db.collection("transactions").where("userid", "==", info.uid).get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
console.log(doc.id, " => ", doc.data());
});
});
});
If you remove the where clause, you get the exact error you are getting

Getting Document Multiple Times in Firestore Rules

When writing rules for a Firebase Database that require fetching a document from a separate collection, is there a difference in referring to that document more than once?
For example, this will cause a single query of the otherStuff collection:
// Rules single get
match /someData/{dataId} {
allow read: if get(/databases/$(database)/documents/otherStuff/$(dataId)).data.allowRead == true
}
But will the following code actively get the same document twice? Or is it optimized, and only fetched once?
// Rules twice get
match /someData/{dataId} {
allow read: if get(/databases/$(database)/documents/otherStuff/$(dataId)).data.allowRead == true
&& get(/databases/$(database)/documents/otherStuff/$(dataId)).data.reallyAllowRead == true
}
Check out this section in the docs, https://firebase.google.com/docs/firestore/security/rules-structure#security_rule_limits
In security rule evaluation for a single rule, "multiple requests for the same document do not count as separate requests."

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