14
votes

In Firebase I have a users "node", which looks like:

users: {
  someUid: {
    username: 'someUsername'
    activeConversations: {},
    profile_picture: ''
    ... lots of other children
  },
  ...
},
anotherNode: {

},
... hundreds of other nodes

My rules right now:

{
  "rules": {
    ".read": true,
    ".write": true,
    "users": {
      ".indexOn": [
        "username"
      ]
    },
    "friendRequests": {
      ".indexOn": [
        "timeSent"
      ]
    }
  }
}

What I want to do is restrict child's access in the users "node" only to the client who owns the child. So for instance, the someUid child should only be writeable by the client with uid someUid. Other "node" like anotherNode can be writeable / readable by any logged-in client. Also, any logged-in client should be able to write on profile_picture and activeConversations in the users doc.

How can I achieve that without having to put a read/write rule on every single node?

Thank you

3

3 Answers

7
votes

I think @Bradley Mackey was nearly there but just needed a small tweak.

{
  "rules": {
    "users": {
      ".indexOn": ["username"],
      // wildcard, matches any node under 'users'
      "$someUid": {
        "$other" : {
          ".read": "($other == 'profile_picture' || $other == 'activeConversations') || auth.uid == $someUid", 
          ".write": "($other == 'profile_picture' || $other == 'activeConversations') || auth.uid == $someUid", 
        }
      }
    },
    "$anythingelse": {
      ".read": "auth != null",
      ".write": "auth != null",
    }
  }
}

The ".validate": field ensures that a field matches a certain format. The read and write here should give everyone read and write access if the field is profile_picture or activeConversations, and give the user access to everything else.

EDIT:

I added in another rule that would allow read-write access to any signed in user to any of the non-users nodes.

4
votes

Having ".read": true, ".write": true at the root of your database is a very bad idea. Literally anyone could just wipe your entire database or insert any data at any time. This is because .read and .write rules cascade, so if you have them evaluating to true at some node, the person has permission for all children of that node as well.

Luckily more secure rules, like the rules you are proposing, are easy to implement. I'm assuming that someUid is equal to the users auth.uid you can do:

{
  "rules": {
    "users": {
      ".indexOn": ["username"],
      // wildcard, matches any node under 'users'
      "$someUid": {
        ".read": "auth != null",
        ".write":"auth != null",
        "$other" : {
          ".validate": "($other == 'profile_picture' || $other == 'activeConversations') || auth.uid == $someUid" // only that own user can change their username
        }
      }
    }
  }
}

I've omitted your friendRequests node, because I'm not sure what security rules you'd like for that, but I hope this is enough to get you started.

The Firebase docs cover this stuff very well.

0
votes

As per the firebase documentation, you can restrict the access permission at user level and data level

For example,

    // These rules grant access to a node matching the authenticated
    // user's ID from the Firebase auth token
    {
      "rules": {
        "users": {
          "$uid": {
            ".read": "$uid === auth.uid",
            ".write": "$uid === auth.uid"
          }
        }
      }
    }

Also you can restrict the read write permission in data level,

{
  "rules": {
    "messages": {
      "$message": {
        // only messages from the last ten minutes can be read
        ".read": "data.child('timestamp').val() > (now - 600000)",

        // new messages must have a string content and a number timestamp
        ".validate": "newData.hasChildren(['content', 'timestamp']) && newData.child('content').isString() && newData.child('timestamp').isNumber()"
      }
    }
  }
}

Go through these firebase official documentation, https://firebase.google.com/docs/database/security/quickstart https://firebase.google.com/docs/database/security/user-security https://firebase.google.com/docs/database/security/securing-data