I'm really scratching my head here, and I've been reading as much as I can on many other cases. I'm new to Firebase, but got some understanding of it. I was wanting to restrict certain records of the database to certain users. So here's my JSON:
"accounts" : {
"13asdf313" : {
"dog" : "bacon",
"email" : "luis#fakeemail.com",
"first" : "luis",
"last" : "xxxx"
},
"HlELrrGDbiMKgxxxx" : {
"name" : "Luis"
},
"anthony" : {
"email" : "anthony#fakeemail.com",
"last" : "xxxx",
"name" : "anthony"
},
"jpSq6UzX0mcAvExxxx" : {
"name" : "anthony"
}
}
Here are the rules set up based on what I've been reading:
{
"rules": {
"accounts":{
"$uid":{
".read": "auth.uid == $uid",
".write": "auth.uid == $uid"
}
},
}
}
In the simulator, I used the bottom condition (I even put /accounts in the location field). I used the UID: HlELrrGDbiMKgxxxx, copied straight from Firebase account list.
This is always coming up as failed
What am I doing wrong?
You have to insert accounts/HlELrrGDbiMKgxxxx into the Location field.
Otherwise you are trying to access the whole database (standard location is root, which covers the whole database). Your rule is just set for the child accounts/$uid and to access it the user id from authentication and the child location in the database must match.
Related
I have a node called profiles that have a list of id's.
I want to allow read access to the child nodes only and prevent reading all profiles.
This is what I have in rules, but it allow to read all profiles.
{
"rules": {
"profiles":{
".read": true,
".write": false
}
}
}
and this is what I have under profiles
{
"1" : {
"id" : "1",
"name" : "test1"
},
"2" : {
"id" : "1",
"name" : "test2"
}
}
Typically you'll store each user's profile under a key that has the value of their Firebase Authentication UID. So:
{
"profiles": {
"uidOfUser1": {
"id" : "1",
"name" : "test1"
}
"uidOfUser2": {
"id" : "2",
"name" : "test2"
}
}
}
In that case you can secure it with these rules:
{
"rules": {
"profiles": {
"$user_id": {
// grants read access to the owner of this user account
// whose uid must exactly match the key ($user_id)
".read": "$user_id === auth.uid"
}
}
}
}
In the security rules the value of auth.uid is the UID of the user that is currently signed in to Firebase Authentication. There is no way to spoof this value, so it's a great way to secure data access. The above rules allow a user to read a specific profile when their auth.uid matches the key of the profile. So uidOfUser1 or uidOfUser2.
Also check out the Firebase documentation on securing user data, which describes it in more detail.
I'm creating an application which lets users create items and then allow other users to subscribe to those items. I'm struggling to craft a rule that will prevent users from subscribing more than once to an item.
Here is an example of my data structure (anonymized, hence the "OMITTED" values):
{
"OMITTED" : {
"name" : "Second",
"body" : "this is another",
"userName" : "Some User",
"userId" : "OMITTED",
"created" : 1385602708464,
"subscribers" : {
"OMITTED" : {
"userName" : "Some User",
"userId" : "OMITTED"
}
}
}
}
Here are my Firebase rules at present:
{
"rules": {
".read": true,
".write": "auth != null",
"items": {
"$item": {
".write": "!data.exists()",
".validate": "newData.hasChildren(['name', 'body', 'userId', 'userName']) && newData.child('userId').val() == auth.id",
"subscribers": {
"$sub": {
".validate": "newData.hasChildren(['userId', 'userName']) && newData.child('userId').val() != data.child('userId').val()"
}
}
}
}
}
}
How can I prevent users from subscribing more than once? What is the rule I need to prevent duplicate users within the subscribers list based on userId?
Since security rules can't iterate a list of records to find the one containing a certain bit of data, the trick here is to store the records by an ID which allows for easy access. There is a great article on denormalization which offers some good insights into this practice.
In this case, if your use case allows, you may simply want to switch your data structure so that records are stored by the user's id, rather than storing the ID as a value in the record, like so:
/users/user_id/items/item_id/subscribers/user_id/
In fact, as you'll see in denormalization, you may even benefit from splitting things out even farther, depending on the exact size of your data and how you'll be reading it later:
/users/user_id
/items/user_id/item_id
/subscribers/item_id/user_id
In either of these formats, you can now prevent duplicates and lock down security rather nicely with something like this:
{
"users": {
"$user_id": { ".write": "auth.id === $user_id" }
},
"subscribers": {
"$subscriber_id": { ".write": "auth.id === $subscriber_id" }
}
}
How can I add new rule to Firebase Realtime Database so that users can read data where recid equal to user ID?
I have a massage table with this structure:
"messages" : {
"-KyyjeMOtc7fWAsOiuiP" : {
"recid" : "FL5hyQJrsHWRQsRtiLe1PxkyRnk1",
"senderid" : "6K6pQHaCishDlCb0Y9AaN3zI22n1",
"text" : "hi"
},
"-KyykczCNpsSL6a1t8vt" : {
"recid" : "FL5hyQJrsHWRQsRtiLe1PxkyRnk1",
"senderid" : "6K6pQHaCishDlCb0Y9AaN3zI22n1",
"text" : "test"
},
}
I want a rule that when data is added to the database, only the user whose uid is equal to recid can see the data.
To achieve this, you can create user-based security rules for your database, something similar to:
{
"rules": {
"messages": {
"$messageId": {
".read": "auth.uid == data.child('recid').val()",
".write": "auth !== null"
}
}
}
}
In this example, $messageId uses a $location variable that will match any key under your messages list. Then, we grant read access only if the current user's auth.uid matches the recid child value.
I'd like to specify rules in Firebase such that a path can only be accessed if it's known.
/root
/messages
/message1
/message2
/message3
If you access /messages you can receive a permission denied (or nothing).
If you explicitly access /messages/message2 you get the contents.
Update 1: Expected behaviour (iOS)
FIRDatabase
.database()
.reference()
.child("invitations")
.observeEventType(.Value, withBlock: { snapshot in
// snapshot returns nothing or permission denied.
})
FIRDatabase
.database()
.reference()
.child("invitations/message1")
.observeEventType(.Value, withBlock: { snapshot in
// snapshot returns message1
})
This is not an answer, but I believe the OP is asking how to prevent enumeration of the nodes under a given node, while allowing anonymous access if the user knows the DIRECT path of a given node.
I too, have been trying to figure out how to do this. Basically, I'm trying to post semi-sensitive data under a given node, while making the name of the node available securely through a different means. However, I don't want to implement a "security/user" model within Firebase. I'd simply like to use Firebase similar to an Amazon S3 bucket, where if you know the location of a key, you can download the file/data stored at that location, while still preventing enumeration/listing of the nodes within the database.
An example of such usage would be if you generate the keyname using a crypto digest such as SHA2. The key couldn't be easily generated, yet if you knew the key, you could access the node directly. Does anyone know how to do this?
EDIT: I figured out how to do this in Firebase. The solution is rather simple. Here is an example of the JSON security rules in Firebase:
{
"rules": {
"users" : {
".read": false,
".write": false,
"$child" : {
".read" : true,
".write" : true
}
},
"chats" : {
".read" : false,
".write" : false,
"$child" : {
".read" : true,
".write" : true,
},
},
"comments" : {
".read" : false,
".write" : false,
"$child" : {
".read" : true,
".write" : true
},
},
".read": false,
".write": false
}
}
In this example, any node under "users", "chats", and "comments" is directly accessible, but enumeration is no longer possible.
You will need to specify the access inside the message id level.
If you were clear on what you are trying to achieve it will look like this:
{
"rules": {
"messages": {
//if you add the read permission here it will give you access to all messages
"$message": {
//here it will give only to the specific $message.
//if you want to specify the exctly message id you can do something like "$message == 'message1'" on the ".read"
".write": "auth != null",
".read": "auth != null"
}
}
}
}
I am new to Firebase, and I was trying to setup security rules where I want users to be grouped by dynamically created groups. I also want the user to be able to read all content from the same group, but not other groups.
When I create new users and assign them some groups using push, I get data like the following:
{
"groups" : {
"default" : {
"-Jtcdyniz1yVwNQCGSAR" : {
"user" : "simplelogin:5"
},
"-Jtd114KNQ-rqh6-rlnI" : {
"user" : "simplelogin:7"
}
}
},
"users" : {
"simplelogin:5" : {
"group" : "default",
"name" : "123"
},
"simplelogin:6" : {
"group" : "default1",
"name" : "1"
},
"simplelogin:7" : {
"group" : "default",
"name" : "23"
}
}
}
Can anyone help here? How can I setup authentication rules? I have tried with following but it doesn't seem to work...
{
"rules": {
"users" : {
"$userid" : {
".read" : "data.child('users').child($userid).child('group').val() === data.child('users').child(auth.id).child('group').val()",
".write" : "$userid === auth.uid"
}
}
}
}
I assume that this should be fairly simple use-case but unfortunately didn't get much help.
Whatever posts that I found had direct users inside a group instead of a subchild of a random, unique string.
EDITED:
I tried with edited rules like :
{
"rules": {
"groups" : {
".read" : "true",
".write" : "true"
},
"users" : {
"$userid" : {
".read" : "data.child('group').val() === root.child('users').child(auth.id).child('group').val()",
".write" : "$userid === auth.uid"
}
}
}
}
but I did not get much help.
For code, I have added it as a fiddler at : http://jsfiddle.net/digish_gabhawala/ytwmokg0/
What I want at the moment is two simple things:
1> as a user, I should be able to edit my name
2> when I click button, I should be able to get names of all users in my group.
When I tried the code as in fiddler, I am getting permission issues.
It would be great if I can get what is it that I am doing wrong.
I'm pretty sure that the issue is that you're using $userid instead of $uid. So changing this should make it work. I'm using $uid in my security rules.