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.
Related
Recently I've received bunch of Firebase notifications regarding:
[Firebase] Your Cloud Firestore database has insecure rules
We've detected the following issue(s) with your security rules:any user can write to your entire database. Because your project does not have strong security rules, anyone can access your entire database. Attackers can steal, modify, or delete your data, and they can drive up your bill.`
Edit2: What I need, is to allow write for everyone without any need to sign in, but only the admin account should be able to read it from Firebase console.
Realtime Database rules:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
Cloud Firestore rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow write;
}
}
}
Edit: One of the Databases structure in JSON, others looks similar:
{
"battles" : {
"-KjiAFLI8oE_12345678" : {
"full" : true,
"player1" : {
"movement" : {
"down" : false,
"left" : false,
"right" : false,
"up" : false
},
"position" : {
"x" : 0,
"y" : 0
}
},
"player2" : {
"movement" : {
"down" : false,
"left" : false,
"right" : false,
"up" : false
},
"position" : {
"x" : 0,
"y" : 0
}
}
},
"-KjiAMVvJydR12345678" : {
"full" : true,
"player1" : {
"movement" : {
"down" : false,
"left" : false,
"right" : false,
"up" : false
},
"position" : {
"x" : 0,
"y" : 0
}
},
"player2" : {
"movement" : {
"down" : false,
"left" : false,
"right" : false,
"up" : false
},
"position" : {
"x" : 0,
"y" : 0
}
}
}
}
}
Edit3: In contrast to the Firebaser's answer to Firebase email saying my realtime database has insecure rules I don't want to/use Firebase Authentication/SSO.
Given these scenario do I have to/shall I modify them somehow?
I can think of two solutions without risking compromising security (to some extent):
You can use Authentication for users and only allow read or write access to authenticated users. (Which I understand is a hassle specially when coding a game.) like so:
match /databases/{database}/documents {
match /{document=**} {
allow write: if request.auth != null;
}
}
}
You can use some sort of 10-char sequence for example combined with the document names in your database (for example, "Users-xQnFiECweq") and then edit your security rules accordingly.
for example:
match /Users-xQnFiECweq {
match /Courses-QrmGvMgF9C {
match /{multiSegment=**}{
allow write;
}
}
}
the string values at the end of document or collection names kind of act as passwords that only you know and it makes it difficult for another person to guess the exact structure to your database.
I understand it's a bit of a strange approach but it's better than giving write access to just everyone.
I get these emails, but there's nothing that can be done to fix mine, because that's just the way my system works.
In your case, the reason is:
allow write;
in your Cloud Firestore rules. This means anyone can access the database from anywhere.
Thus,
Attackers can steal, modify, or delete your data, and they can drive up your bill.
Change this rule to only allow authenticated access, and the alert should stop.
A super admin is an user with special uid which is able to access of everyone to edit their profile and publish new content.
How to make a super admin?
Consider using custom user attributes. It is more efficient and cheaper than using Real Time Database to lookup if a user is an Admin on every authenticated request:
https://firebase.google.com/docs/auth/admin/custom-claims
You would set the Admin role on the user upon creation:
admin.auth().setCustomUserClaims(uid, {admin: true})
You can propagate it to the client after ID token refresh.
currentUser.getIdToken(true)
Then you can simply enforce the rule:
{
"rules": {
"adminContent": {
".read": "auth.token.admin === true",
".write": "auth.token.admin === true",
}
}
}
If you don't use rules or Firebase RTDB, then enforce it on your backend by parsing it from the ID token via Firebase Admin SDK:
// Verify the ID token first.
admin.auth().verifyIdToken(idToken).then((claims) => {
if (claims.admin === true) {
// Allow access to requested admin resource.
}
});
Basically, it's all about data structure and the belonging security rules.
To get started, build a data structure where you have some kind of user roles in it.
For example like this:
{
"data" : {
"user1id" : {
"name" : "MisterX"
},
"user2id" : {
"name" : "John Doe"
}
},
"users" : {
"user1id" : {
"role" : "admin"
},
"user2id" : {
"role" : "member"
}
}
}
Each user has a property called role.
Now you can define your security rules and make use of the role property to define the right access rights:
"data" : {
"$userid" : {
".read" : true,
".write" : "root.child('users').child(auth.uid).child('role') === 'admin'",
}
}
In the case above just admins are able to write to the data/userid node. You can apply this to all the different nodes you want to.
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.
JSON looks like this:
"messages" : {
"msg" : {
"-Kr2Qb93tM7yP-J7zuAq" : {
"text" : "hello",
"toId" : "EeLIxkOEfhMUlsM8WGnHdgeT8xW2",
"fromId" : "IxfnlsekOh8WEG2HdgMUMWT8xEeL"
}
}
}
How can i only give read permission for "-Kr2Qb93tM7yP-J7zuAq" to user if "toId" 's value contain his uid?
And "fromId" can Edit\delete the snapshot.
Thanks!
Change your Firebase Realtime Database Rules to the following :-
rules": {
.
.
"messages" : {
"msg" : {
"$messageID" :{
".read" : "data.child('toId').val() == auth.uid",
".write": "data.child('fromId').val() == auth.uid"
}
}
}
}
Also, what you're asking is pretty basic. So, I would really recommend you to read up on Firebase Rules here.
I'm working thru the excellent example on how to structure data as shown by Kato in this post:
Firebase user account security with firebaseSimpleLogin
I'm not having any luck getting validate to work properly.
The data structure is :
accepted_invites
game1
desc "fun game"
invites
game1
uuidAAA true
uuidBBB true
here's a screen shot:
Firebase data
If I try and write the following
ref.child("accepted_invites").child("game1").child("userTwo").child("uuidBBB").setValue(true);
it will make an entry in accepted_invites with this rule :
".validate": "root.child('invites/'+$game_id+'/uuidBBB').exists()"
but not
".validate": "root.child('invites/'+$game_id+'/'+newData.val()).exists()"
I tried using the simulator but I'm getting
Type Error: + only operates on numbers and strings.
Here's the complete rules as I have them:
{
"rules": {
".write" : true,
".read" : true,
"accepted_invites": {
"$game_id": {
"$user_id": {
//This validate rule fails
//".validate": "root.child('invites/'+$game_id+'/'+newData.val()).exists()"
//This one works
".validate": "root.child('invites/'+$game_id+'/uuidBBB').exists()"
}
}
}
}
}
The newData keyword is a special attribute referring to all incoming data, but it is not permitted in path expressions because it may not be a string. i.e., it could very well be an object.
If you're interested in using some portion of that data within the path, I would recommend just including another validation rule at a deeper path, such as:
{
"rules": {
".write" : true,
".read" : true,
"accepted_invites": {
"$game_id": {
"$accepting_user_id": {
"$sending_user_id": {
".validate": "root.child('invites').child($game_id).child($sending_user_id).exists()"
}
}
}
}
}
}