Firebase Realtime Database Security Rules - How to get into second node - firebase

I am struggling with the security rules on the firebase realtime database. My database structure is as following:
On the first level you have Chats. On the second level there are the Chat partners (a concatenated string with user IDs of chat partners). On the third level you have the messages. And on the last level there are the variables datetime, userid and message.
My question is, how can I get into the second child node, e.g. check if the auth.uid is within the concataneted string. My idea was to give the users read access, if the userid is within the chatpartners string, to ensure that only the chatpartners can read their messages. Or is this a thinking error?
I have tryid a lot of things, however no success:
"Chats":{
".read": "root.child('Chats').val().contains('auth.uid')"
}
#Update
{
"rules": {
"Chats": {
"$chatid": {
".read": "$chatid.contains(auth.uid)",
".write": "auth != null"
}
},
"Suchencards": {
".read": "true",
".write": "auth != null"
},
"UserData": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
I am using the playground on firebase console to check if I get true or false, however in that case I get false.
#Update 2
Screen1
Screen2

You can only access data in your rules if you know the exact path to that data, so you won't be able to access all chats from a rule on /Chats. Trying to do so typically means that you're trying to define your rules on the wrong level.
For example, if you want to allow a user to read a specific child of Chats, you'll need to define rules on that level:
"Chats":{
"$chatid": {
".read": "$chatid.contains(auth.uid)"
}
}
While the above will work for accessing a specific room, you will not be able to use this to query for all chat rooms that a user has access to (as Firebase queries don't support a "contains" operation). Have a look at the userChatrooms node in my answer here for a better model for tracking the chat rooms for a user: Best way to manage Chat channels in Firebase

Related

Firebase Your Realtime Database has insecure rules

I have been getting email notifications about my Firebase rules not being secure even though I set the data to be readable only by authenticated users and I set the write to be false. My application basically shows currency exchange rates and I create an anonymous user once the app loads for the user to be able to read the data so I think it makes sense to have such rules? Here are my rules:
{
"rules": {
".read": "auth.uid != null",
".write": false
}
}
Update: I updated my rules to:
{
"rules": {
"currencies":{
".read": "auth.uid != null",
},
".write": false
}
}
And here is my data:
(https://i.stack.imgur.com/in1BV.png)
I set the data to be readable only by authenticated users
While that is a good starting point, it means I can get all your (user's) data by signing in and reading the root. This is not secure and open to abuse, which is why you receive alerts about it.
You should follow the principle of least privilege, and only allow in your rules exactly what your code does.
In the unlikely event that your code really reads the root, you can disable the alert in the Firebase console.
In all other cases, you'll want to reduce the read permission to exactly how your code reads it. For example, if your code reads from two top-level nodes, you can secure that with:
{
"rules": {
"users": {
".read": "auth.uid != null",
},
"messages": {
".read": "auth.uid != null",
},
".write": false
}
}
In a scenario like this, you're likely to read the /messages first, and then read the profile information for specific users mentioned in those messages. You can better secure that like this:
{
"rules": {
"users": {
"$uid": {
".read": "auth.uid != null",
}
},
"messages": {
".read": "auth.uid != null",
},
".write": false
}
}
Now a malicious user can't read all of /users in one go, but can read the profile only once they know the UID. A sufficiently motivated user can still read your entire database, but it'll take a lot more effort - which discourages abuse.
Also think of whether the user needs to read all message, or (say) maybe just the 50 most recent ones. The latter use-case you can secure better with query based security rules:
"messages": {
".read": "auth.uid != null &&
query.orderByChild == 'timestamp' && &&
query.limitToLast <= 50"
},
Now the user can only read the 50 most recent messages, and thus (with the previous) also only the user profiles that participated in those messages.
Finishing off with the golden rule: only allow in your rules exactly what your code does. Make sure your code works, but any different API calls get rejected.

Firebase create RTDB object if property name is uid [duplicate]

I am trying to block hackers from modifying or seeing the data on my Firebase database. Users in my database contains the user IDs of all the users in Authentication tab. Can I make the database to only let see data by the user logged in?
This is my database structure:
firebase database structure
I want to allow users to modify their own user ID's entry in "users" and I want to allow only the admin to control "orders". Im using Firebase in a Electron app so client is connecting to firebase in Node.js
Yes, this is definitely doable using Firebase Database Rules
What you've described seems like it would have three parts, but they we they combine also affects how you need to write them.
I'll start by going over the 3 pieces separately and then will move into combining them.
Read/Write By Only Logged In Users
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
By placing this at the top level of your rules, you will prevent any reading or writing by anyone not logged in through one of the supported Firebase authentication methods.
Users Modifying User Entry
{
"rules": {
"users": {
"$uid": {
".write": "auth.uid === $uid"
}
}
}
}
This specifies that under the user path, for each user id (using the $uid syntax to specify it as a variable to be used later), only allow writing when the current authenticated user id matches that same id.
Admin Control Of Orders
{
"rules": {
"orders": {
".read": "auth != null && auth.token.isAdmin",
".write": "auth != null && auth.token.isAdmin"
}
}
}
We take a similar approach for orders as we did for users entries, but instead of checking the user id we simply say that only an admin can do reads and writes anywhere under orders.
Putting It All Together
Now, if these rules came together in a way such that more specific rules overrode less specific rules (like CSS selectors, for instance), then we could simply merge all of the above together like this:
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"orders": {
".read": "auth != null && auth.token.isAdmin",
".write": "auth != null && auth.token.isAdmin"
},
"users": {
"$uid": {
".write": "auth.uid === $uid"
}
}
}
}
However, Firebase database rules are somewhat of an inverse of this. Providing access in shallower rules will override any deeper rules attempting to deny access (although it is possible to grant more privileges in deeper rules). So the above will actually give full read/write access to the entire DB by any logged in user.
In light of that, we will need to be more careful when combining these, to ensure that our separate intents stay valid. Most importantly, the first section Read/Write By Only Logged In Users will be the section that requires modification, since it was at the top level.
Luckily, our rules from parts 2 & 3 take care of most of what we were getting from part 1 anyways. This only holds true if there are only orders and users in your db. The only thing we are missing is a read rule on users. It's not entirely clear what sort of rules you want for reading user data, since you only specify that a user can only write his or her own data, so I will assume that all logged in users can read user data.
The merge then becomes:
{
"rules": {
"orders": {
".read": "auth != null && auth.token.isAdmin",
".write": "auth != null && auth.token.isAdmin"
},
"users": {
".read": "auth != null",
"$uid": {
".write": "auth.uid === $uid"
}
}
}
}
Please note that you will need to duplicate the auth != null rule for read and/or write in other nodes of your db if you have them, since here you only show off orders and users.
Hope that helps!

Firebase auth database rules

I am working on the app that I need to connect to the dev firebase.
This firebase has database rules as follows:
"rules": {
// no read access at root level
".read": "auth.uid === 'emailaddressgmailcom'",
".write": false,
What I cannot understand is how auth.uid is specified to be an exact email address?
As far as I tried I only get unique uid provided by Google. (set of numbers and letters)
Hence I can never pass the auth to read from the database, unless I specify my exact uid given by Google in the databse rules, which is not an option because there will be another user who needs an access to db and I do not know his uid.
auth is one of the predefined variables.
By doing auth.uid, you get the user id ("guaranteed to be unique across all providers").
You need, in your Security Rules to use it to defined the access rights of a given user to one or more given resources, as explained here in the doc.
You could compare it to a fixed value, if a certain resource shall be read by a unique user:
".read": "auth.uid === 'HGH656675FHGFGHF3454'"
but usually you compare it to some parts of the path of the node/resource you want to protect, like for example:
{
"rules": {
"users": {
"$user_id": {
// grants write access to the owner of this user account
// whose uid must exactly match the key ($user_id)
".write": "$user_id === auth.uid"
}
}
}
}
This is how you should do to solve your problem "there will be another user who needs an access to db and I do not know his uid".
I would suggest you read the entire section about RTDB Security Rules form more details: https://firebase.google.com/docs/database/security
Please try below rules
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
// These rules grant access to a node matching the authenticated
// user's ID from the Firebase auth token

How to access parent auth status in array

I'm not sure whether the title of this is appropriate as I'm new to Firebase Authentication and rules, however, I have successfully setup authentication and am now trying to protect a particular route and can't seem to access the relevant data, here's my Firebase rules on my realtime database:
{
"rules": {
"accounts": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
},
"demo": {
".read": "accounts.$uid === auth.uid",
".write": true
}
}
}
As you can see, I'm trying to access the accounts/$uid/ from within "demo", it doesn't seem to work, what am I missing/what do I need to change?
Many thanks
UPDATE
The code in question not working is:
".read": "accounts.$uid === auth.uid"
I can't seem to access this part. It doesn't seem to get the current user's authentication status.
UPDATE
See attached screenshot for my attempt on using a predefined variable. I'm simply trying to get the auth status and I'm getting an error saying it's undefined?
The UID of the current user who is trying to access the data is available in auth.uid. If you're trying to ensure that a read of quotes is only allowed if the user has a document in the accounts node, you're looking for exists().
"website-quotes": {
".read": "root.child('accounts').child(auth.uid).exists()"
}

firebase realtime database security rules for non user data

So, I have an app where users can order the cakes and do other profile management, the rules looks like below:
{
"rules": {
"cakes" : {
".read": true,
".write": false
},
"users": {
"$user_id": {
".read": "auth != null && $user_id === auth.uid",
".write": "auth != null && $user_id === auth.uid"
}
}
}
}
Simply, they mean any one can read the cakes node (but no one can write). And an authenticated user can see or write to his on node.
This is good so far.
Now, my requirement is: When someone places an order through the app then i need to store it to firebase db in a top level node (lets say it orders). The question is what kind of security would be placed on orders node?
In functional definition: The app should be able to create new orders as user checks out, no one except seller should be able to read those orders, only seller should be able to have update access to a order.
If you want everybody to be able to write orders, and nobody able to read, the rules are simply the inverse of the ones for cakes:
"rules": {
"orders" : {
".read": false,
"$orderId": {
".write": true
}
},
With this anyone can push new data under /orders. And as long as you use push() to generate the new keys, you're guaranteed that they'll never conflict.
With these rules only a system-level admin can read the data. That is: you can read it in the Firebase Console, or someone can read it if they use the Admin SDK.
You might want to open it up for reading a bit more, e.g. by having the concept of an application-level administrator. Say that your UID is uidOfVik, you could model a list of admins in your database:
admins: {
uidOfVik: true
}
Now you can allow only admins to read the orders with:
"rules": {
"orders" : {
".read": "root.child('admins').child(auth.uid).exists()",
"$orderId": {
".write": true
}
},

Resources