Security rule strange behaviour? - firebase

allowed access with blank UID
DATA
{
"roles": {
"admins": {
"123456789": {
"name": "Max"
}
}
},
"meta": {},
"events": {
"3423556": {
},
"meta": {
}
},
}
}
RULES
"rules": {
"events": {
".read": "root.child('roles').child('admins').hasChild(auth.uid)",
}
}
it returns faile if I'm trying
Type read Location /events/ Data null Auth { "provider": "anonymous",
"uid": "1" } Admin false
and true if UID is blank
Type read Location /events/ Data null Auth { "provider": "anonymous",
"uid": "" } Admin false

Related

Read subset of firebase realtime database with rules restrictions

I have a firebase real-time database structured like this:
{
"USERS": {
"user-1": { ... },
"user-2": { ... }
}
"GROUPS": {
"group-1": {
"id": "group-1",
"AUTH": {
"user-1": true,
}
},
"group-2": {
"id": "group-2",
"AUTH": {
"user-2": true
}
},
"group-3": {
"id": "group-3",
"AUTH": {
"user-1": true,
"user-2": true
}
}
}
}
I know that I can give read permissions that would give read access to users that only belong to a specific group, like this:
{
"rules": {
"GROUPS": {
"$groupId": {
".write": false,
".read": "auth != null && data.child('AUTH').child(auth.uid).exists()"
}
}
}
}
I'm trying to find a query + rules combination that would return me all the groups that the logged in user belongs to.
For example:
A query and firebase rule change that for logged in 'user-1' returns a snapshot of:
{
"group-1": {
"id": "group-1",
"AUTH": {
"user-1": true,
}
},
"group-3": {
"id": "group-3",
"AUTH": {
"user-1": true,
"user-2": true
}
}
}
OR
[
{
"id": "group-1",
"AUTH": {
"user-1": true,
}
},
{
"id": "group-3",
"AUTH": {
"user-1": true,
"user-2": true
}
}
]
querying for the "GROUPS" reference now give me a 'permissions denied' error.
adding '.read=true' to the GROUPS:
{
"rules": {
"GROUPS": {
".read": true,
"$groupId": {
".write": false,
".read": "auth != null && data.child('AUTH').child(auth.uid).exists()"
}
}
}
}
or any combination for '.read' that passes the condition, gives everyone access to all the data.
Is there a way (in the current structure) to query the database and get from the "GROUPS" branch all the groups that I belong to by adding some restriction to the rules?
or do I need to maintain under each user the list of the group that he belongs to?

How to structure my data in Firebase

I'm new to the data structure with Firebase.
I read this: https://firebase.google.com/docs/database/ios/structure-data
I understood that it was necessary to use a flattened structure.
But I'm not sure how to do that in real world.
And I think that to use the Firebase rules correctly I need a suitable structure (but I have no experience with that).
I have 2 types of data:
A list of parts :
parts: {
part1: {
chapter1: {
lesson1,
lesson2,
...etc
},
chapter2: {
lesson1,
lesson2,
...etc
},
chapterX: {
...etc
},
},
part2: {
chapter1: {
lesson1,
lesson2,
...etc
},
chapterX: {
...etc
},
},
partX: {
...etc
}
}
And a list of users :
users: {
user1: {
name,
email,
...etc
},
user2: {
name,
email,
...etc
},
user3: {
...etc
},
etc...
}
Each user can validate a lesson and its progress must be saved.
If the user validates all the lessons: he validates the chapter.
And if he validates all chapters: he validates the part.
I am thinking about to structure my Firebase database like this:
{
users: {
$uid: {
name,
email,
...
}
},
checked: {
user1: {
parts: {
part1: true
},
chapters: {
chapter1: true,
chapter2: true
},
lessons: {
lesson1: true,
lesson7: true,
lesson15: true,
}
},
user2: {
parts: {
part3: true
},
chapters: {
chapter1: true
},
lessons: {
lesson18: true,
lesson57: true,
}
}
}
}
And for Firebase rules:
{
"rules": {
"users": {
"$uid": {
".write": "$uid === auth.uid"
}
},
"checked": {
"$uid": {
".write": "$uid === auth.uid"
}
}
}
}
Is this the right way to go?
Are the rules OK?
Thanks!
Based on the information you provided, you are doing the right way. And the rules are OK. The structure of your database fits the way you want to read them so you are doing the right way.

Firebase database security rules and dollar signs

I'm creating a Google docs type of app where multiple users can edit a document in real-time.
These are my security rules:
{
"rules": {
"docs": {
"$doc_id": {
".read": "auth.token.doc_id === $doc_id",
".write": "auth.token.doc_id === $doc_id"
}
}
}
}
This is my Auth token payload (example)
{
"provider": "anonymous",
"uid": "e71afdf1-2b31-4c75-8f10-a9b0f916915e",
"token": {
"doc_id": 11
}
}
So when I try to read this path /docs/11/data I get a Simulated read denied error.
On the other hand when I put this rule instead
".read": "auth.token.doc_id === 11", (i.e. hard code $doc_id as 11)
The read passes.
But isn't $doc_id equal to 11 when I read /docs/11/data or am I misunderstanding something?
P.S. In case it matters, here is the data inside my database
{
"docs": {
"2": {
"data": {
"title": "test"
}
},
"11": {
"data": {
"title": "test"
}
}
}
}

Firebase complex rules

Let's assume I have the following data structure in my Firebase database:
{
"allProjects": {
"foo": true,
"bar": true,
"baz": true
},
"allUsers": {
"user1": true,
"user2": true,
"user3": true
},
"projects": {
"foo": {
"name": "foo",
"members": {
"user1": true
}
},
"bar": {
"name": "bar",
"members": {
"user2": true
}
},
"baz": {
"name": "baz",
"members": {
"user1": true,
"user3": true
}
}
},
"users": {
"user1": {
"name": "user1"
},
"user2": {
"name": "user2"
},
"user3": {
"name": "user3"
}
}
}
Problem
I'm trying to write a few rules so I can protect my data. Here's a few requirements:
Users should only see projects they are part of (i.e. /project/:id/members/:userId === true)
Users should only see users that belong to the same projects as them.
Here's what I was able to come up with:
{
".read": false,
".write": false,
"allProjects": {
".read": "auth !== null"
},
"allUsers": {
".read": "auth !== null"
},
"projects": {
"$projectId": {
// requirement 1
".read": "data.child('members').hasChild(auth.uid)"
}
},
"users": {
"$userId": {
// requirement 2
".read": "???",
}
}
}
The typical approach would be to keep a list of users that each user can see.
user_friends: {
"user1": {
"user3": true
}
"user3": {
"user1": true
}
}
Then as users get added to/removed from projects, you'll need to keep this derived list up to date. Alternatively you can calculate this derived list in a schedule maintenance operation.
Duplicating data like this is one of the big differences between SQL databases and most NoSQL databases. In Firebase we often store extra data to allow for our use-cases. For a great introduction I recommend reading NoSQL data modeling and watching Firebase for SQL developers.
By the way, I noticed that you've combined metadata and the list of users under /projects/$projectid. This is not recommended. For best results, split them into two top-level lists.
"projects": {
"foo": {
"name": "foo",
},
"bar": {
"name": "bar",
},
"baz": {
"name": "baz",
}
},
"members": {
"foo": {
"user1": true
},
"bar": {
"user2": true
},
"baz": {
"user1": true,
"user3": true
}
},

I can't get the user uid signed in in the rules of the firebase console

Here is my data.
"users" : {
"user1": {
"1234": {
"role": "admin"
},
"1235": {
"role": "normal"
}
},
"user2": {
"1236": {
"role": "admin"
},
"1237": {
"role": "normal"
}
}
}
And here is rules for that.
"rules" {
"users": {
".read": "root.child('users').child('user1').child(auth.uid).child('role') === 'admin'"
}
}
But the rule doesn't work. I seem the auth.uid isn't gotten correctly.
Try this :-
{
"rules": {
"users": {
"user1": {
"$user_id": {
".read": "$user_id === auth.uid && root.child('users/user1/' + $user_id + '/role/').val() === 'admin' "
}
}
}
}
}

Resources