How prevent retrieve a child in same parent node? - firebase

I want to read all usernames from users parent node, because I'm using search feature in my app (if provided searchActive: true child in users node). But email need to be reachable only by owner.
I have just tried like below, but I'm still getting email. I'm worried about security not only email, What I'm missing and How Can I organize all of them?
"rules": {
"users": {
".read": "auth !== null",
"$uid": {
".write": "auth !== null && auth.uid === $uid",
".read": "auth !== null && auth.uid === $uid",
"username": {
".validate": "
!root.child('usernames').child(newData.val()).exists() ||
root.child('usernames').child(newData.val()).val() == $uid"
},
"email": {
".read": "auth.uid == 'facebook:'+$uid || auth.uid == $uid"
}
}
},
"usernames": {
".write": "auth !== null",
".read": "auth !== null"
},

First the reason why you can still access email is because rules cascade meaning when you set read to true for the parent node all the children can also be read. In your case:
"users": {
//Read is being set to true here for everything in this node
".read": "auth !== null",
"$uid": {
".write": "auth !== null && auth.uid === $uid",
//This will be ignored, since read was allowed already
".read": "auth !== null && auth.uid === $uid",
"username": {
".validate": "
!root.child('usernames').child(newData.val()).exists() ||
root.child('usernames').child(newData.val()).val() == $uid"
},
"email": {
//This will be ignored, since read was allowed already
".read": "auth.uid == 'facebook:'+$uid || auth.uid == $uid"
}
}
},
"usernames": {
".write": "auth !== null",
".read": "auth !== null"
},
I suggest you take some time to read all the documentation about firebase security. It can really help you avoid situations like this and perhaps give you some idea's about implementing a good security for your case.
A possible solution is to use a seperate username node where you store all the usernames for your search feature. You can use the rules to make sure everyone can read it but only the owner of a specific username can change it.

Related

Firebase Rules: We've detected the following issue(s) with your security rules

appreciate this looks like this is been answered various times for individual requirements. Completely new to Firebase and I want to get some insight into this. I have been presented with the message from Firebase.
We've detected the following issue(s) with your security rules:
any logged-in user can read your entire database
any logged-in user can write to your entire database
My current rules look like this:
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"items": {
".indexOn": "ownerId"
},
"events": {
".indexOn": "ownerId"
},
"contacts": {
".indexOn": "ownerId"
}
}
}
Based on the documentation, Do I simply need to do this?
{
"rules": {
".read": "auth != null && auth.uid == $uid"
".write": "$user_id === auth.uid",
"items": {
".indexOn": "ownerId"
},
"events": {
".indexOn": "ownerId"
},
"contacts": {
".indexOn": "ownerId"
}
}
}
Will users still be able to access their own (previously) written data prior to making the change while enforcing the security rules from Firebase.
Apologies if this a silly question, but got a lot of data which I cannot let users not have access to.
Thanks
As firebase documentation says:
Sometimes, Rules check that a user is logged in, but don't further restrict access based on that authentication. If one of your rules includes auth != null, confirm that you want any logged-in user to have access to the data.
So you have to get rid of this part down under the rules part:
".read": "auth != null",
".write": "auth != null",
And use any of these approaches: Content owner only, Path-delineated access or Mixed public and private access.
For example:
{
"rules": {
"products": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid",
".indexOn": ["creatorId", "isActive"]
}
},
"stores": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid",
".indexOn": ["creatorId", "isActive"]
}
},
"orders": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid",
}
},
}
}

My Firebase Security Rule won't allow me to write on another user's node, why?

I have tried a few things but none worked...
I'm implementing a "block user" functionality in my app, when user A blocks user B, I am writing to a child node of both users's block-user and blocked-by-user child nodes respectively.
Error: setValue: or removeValue: at /users/$uid/blocked-by-users/-LPi46QePJLDWIrrU45y failed: permission_denied
I wish to update the following rule to allow to write on another user's uid child nodes called blocked-users and blocked-by-users
"users": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "auth.uid == $uid"
},
".read": "auth != null"
},
please help!
"users": {
".write": "auth != null",
".read": "auth != null"
},
This will work, if you don't have any security issue:)

Firebase Database Rules to match row

I am using a Firebase Realtime Database. I have the following data:
I also have the rules:
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"chat": {
"$key": {
".read": "data.child('memberId1').val() === auth.uid && data.child('memberId2').val() === auth.uid",
".write": "data.child('memberId1').val() === auth.uid || data.child('memberId2').val() === auth.uid"
}
},
The initial rule works perfectly:
".read": "auth != null",
".write": "auth != null",
Problem
The following 2 rules have no effect.
"chat": {
"$key": {
".read": "data.child('memberId1').val() === auth.uid && data.child('memberId2').val() === auth.uid",
".write": "data.child('memberId1').val() === auth.uid || data.child('memberId2').val() === auth.uid"
}
},
As you can see, in order to test these rules, in the first rule, I have made an impossible condition of memberId1 and memberId2 both equal to the users uid. As a result I would expect it to fail.
If I remove:
".read": "auth != null",
".write": "auth != null",
and just have:
"chat": {
"$key": {
".read": "data.child('memberId1').val() === auth.uid || data.child('memberId2').val() === auth.uid",
".write": "data.child('memberId1').val() === auth.uid || data.child('memberId2').val() === auth.uid"
}
},
Then access is denied. Even if I change it to:
"data.child('memberId1').val() === 'h6qQg5YfQveTaCyBEXwDMSJPqwk1'
The following is also denied:
"chat": {
"Ko7w9XTtuRVN4p6CMp7": {
".read": true,
Question
How should I structure the rules to allow that a user may only access a row where their uid matches either memberId1 or memberId2?
Thanks
UPDATE
I have the following code:
findChats(): Observable<any[]> {
return this.af.database.list('/chat/', {
query: {
orderByChild: 'negativtimestamp'
}
}).map(items => {
const filtered = items.filter(
item => (item.memberId1 === this.me.uid || item.memberId2 === this.me.uid)
);
return filtered;
});
}
My question is similar to this one. I try the following with no success:
{
"rules": {
"chat": {
"$id": {
".read": true
}
},
Firebase rules are atomic. So if you try to read /chat (and thats what you are currently doing) it will only check the /chat branch rules. Since you dont have any rule in /chat it goes for the default thats is not giving access. Therefore, your rules would only be evaluated in case you were trying to read /chat/chatId.
One possible solution you could go for is to store a list of chats which each user is part of. So you can keep your current chat branch but store another branch in the database with the following structure:
user_chats: {
uid1: {
chatId1: true,
chatId2: false
}
uid2: ...
}
And rules:
"user_chats": {
"$uid": {
".read": "auth.uid === $uid",
".write": "auth.uid === $uid"
}
}
Then you could keep your chat rules like you already have them but first get the data from /user_chats/uid and then for each chatId retrieved you you will need to read on chat/chatId.

Firebase Rules Flat structure for stores, user, products relationship

i try to build a firebase Datastructure.
i come from a SQL world and have Problems understanding noSQL Datastructur.
i would like to have a Datastructure for Stores.
Each Store has some Datafields like Storename, Address and so on.
A Store should also have a Users Object storing all the Users that work in this Store and are able to add new Products and modify them.
There is also a Dataobject that stores the Products and the Products should
have also a relation to the users(stores).
Can someone give me a hint how to build this as flat as possible?
My data structure right now:
"rules": {
"users": {
"$uid": {
".write": "auth !== null && auth.uid === $uid",
".read": "auth !== null && auth.provider === 'password'"
}
},
"products": {
"$uid": {
".write": "auth !== null && auth.uid === $uid",
".read": true
}
},
"stores": {
"$uid": {
".write": "auth !== null && auth.uid === $uid",
".read": true
}
}
}
Thanks

Access a node/path by two specific users only

I've read up and tried denormalization and while it makes perfect sense for cases like comments/messages that are accessible publicly while a user can only write to his own path/node, I'm having a hard time restricting ".read" rule to the user/owner AND to another user/admin. My use case doesn't publicly post all messages. To expound, for example, messages by user1 are only readable by user1 and admin, while still retaining write-only to user1.
How is this achieved? In security rules, I tried:
"messages": {
".read": "auth !== null",
".write": "auth !== null",
"$message": {
".read": "data.child('userID').val() === auth.uid"
}
}
OR
"messages": {
".write": "auth !== null",
"$message": {
".read": "data.child('userID').val() === auth.uid"
}
}
OR
"messages": {
"$user_id": {
".read": "auth.uid === $user_id"
".write": "auth.uid === $user_id"
}
}
While the last one does restrict reading and writing to the authenticated user, say user1, I had no luck getting the admin user to get all users' messages. The first, I can't circumvent the cascading/top-down rule.
I'm a firebase newbie so if this is really simple to do, I appreciate any helping hand.
Thanks!
This depends on how you define an administrator.
Let's first say that your admin is a known user with uid SOF.
"messages": {
"$user_id": {
".read": "auth.uid === $user_id || auth.uid == 'SOF'"
".write": "auth.uid === $user_id"
}
}
If you want the administrator to be configurable, you'll probably store their ID somewhere else, say in a node called administrators:
administrators
SOF: true
Frank: true
messages
...
In that case your can check if the current uid is either in the current node or it exists in the list of administrators:
"messages": {
"$user_id": {
".read": "auth.uid === $user_id || root.child('administrators/'+auth.uid).exists()"
".write": "auth.uid === $user_id"
}
}
Update
Since you want administrators to be able to read all messages, you'll end up with:
"messages": {
".read": "root.child('administrators/'+auth.uid).exists()",
"$user_id": {
".read": "auth.uid === $user_id",
".write": "auth.uid === $user_id"
}
}

Resources