8
{
  "rules": {
       "users": {
            "$uid":{ 
                 //Private whatever under "uid" but Public is exposed
                 ".read": "auth != null && auth.uid == $uid",
                 ".write": "auth != null && auth.uid == $uid",

                 "public": { ".read": "auth != null" }
                 }
               }
            }
}
  • I've created these rules to have users public/private profile
  • "users/{uid}/public" profile should be accessible by any users those are authenticated, but cannot access the data under "users/uid"

Here is some fake data that is stored in my firebase database.

{
  "users" : {
    "YFIIAgwa2kaannrXjwvSZmoywma2" : {
      "Name:" : "Example 1",
      //This public child should be accessible by 
      //"Example 2" but cannot know the name of 
      // this user
      "public" : {
        "email" : "example1@gmail.com"
      }
    },
    "YgSfSzPzxLbyDL17r6P9id2cdvH2" : {
      "Name:" : "Example 2",
      //This public child should be accessible by 
      //"Example 1" but cannot know the name of 
      // this user
      "public" : {
        "email" : "example2@gmail.com"
      }
    }
  }
}

I want to know if this is the robust way to prevent any users from accessing user's critical information! Is there anyway I can improve this by using validate? I am open to any suggestions you guys have. I want to create the best and simple security rules for my app.

user2884707bond
  • 559
  • 4
  • 24

2 Answers2

12

You can definitely secure access to the private and public data with your current data structure.

But one use-case you'll likely want at some point is to show a list of the public info for all users. With your current data structure that is not possible, because Firebase's security model cannot be used to filter data. For a great answer covering this, see Restricting child/field access with security rules.

Most developers split the public and private data in completely separate subtrees:

{
  "users" : {
    "YFIIAgwa2kaannrXjwvSZmoywma2" : {
      "Name:" : "Example 1",
    },
    "YgSfSzPzxLbyDL17r6P9id2cdvH2" : {
      "Name:" : "Example 2",
    }
  },
  "public_profiles": {
    "YFIIAgwa2kaannrXjwvSZmoywma2" : {
      "email" : "example1@gmail.com"
    },
    "YgSfSzPzxLbyDL17r6P9id2cdvH2" : {
      "email" : "example2@gmail.com"
    }
  }
}

You can then secure access with:

{
  "rules": {
     "users": {
        "$uid":{ 
             ".read": "auth != null && auth.uid == $uid",
             ".write": "auth != null && auth.uid == $uid",
        }
     },
     "public_profiles": {
        ".read": "auth != null",
        "$uid":{ 
             ".write": "auth != null && auth.uid == $uid",
        }
     }
  }
}

Now any authenticated user can listen to /public_profiles, which means you can easily show a list of these profiles.

Community
  • 1
  • 1
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
1

Hmm wouldn't it be easier to (re)structure the db so that you have a public and a private field per user? Something like:

{
  "users" : {
    "YFIIAgwa2kaannrXjwvSZmoywma2" : {
      "private": { 
        "Name:" : "Example 1" 
      },
      "public" : {
        "email" : "example1@gmail.com"
      }
    },
    "YgSfSzPzxLbyDL17r6P9id2cdvH2" : {
      "private": { 
        "Name:" : "Example 2" 
      },
      "public" : {
        "email" : "example2@gmail.com"
      }
    }
  }
}

/UPD: This way it should be easy(er) to have the different permissions because they won't inherit them from the parent?

REJH
  • 3,273
  • 5
  • 31
  • 56
  • I like how you have it separated. I suppose I can do that, but wouldn't it create a problem of nesting in the future when I want to add more data to it! Is there any way we create a separate tree for public data? – user2884707bond Aug 12 '16 at 16:24
  • You could use the public profile for the "default" data and use that to look up additional things in the private field. That way you won't have the mess of duplicate fields in private and public that have the same data. You request the public data, then the private and merge them on the client side – REJH Aug 12 '16 at 16:59
  • 1
    I frequently use this technique on all my resources in Firebase. In fact.. even resources that are public only, I still namespace with a `public/`, so they can be future proof. – Roy Kolak Aug 26 '16 at 19:36
  • In the model in my answer you could attach a listener to `/public_profiles` to get a list of the public information across all users. I don't think that's possible in the model you have. – Frank van Puffelen Mar 07 '17 at 05:08