2

How to filter out/hide secret attributes in Firebase?

For example, if I have a data store:

"people": {
  "ivan": {
    "age": 23,
    "location": "Australia"
    "password": "123",
    "underGroundLover": "JLo"
  }
}

I want to hide password and underGroundLover from general audiences while they are able to fetch node ivan.

From my understanding, Firebase's authorisation/security rule/node fetching logic is simply "all or nothing", so that if I want to filter out some secret properties from a node, I will have to either:

  1. Use my own server/lambda to filter out secrets before passing data to users. Which defeats the purpose of BAAS.

  2. Use a weird denormalised data structure to separate public accessible and permission-required attributes. Which will introduce a large amount of n+1 queries.

Option 2's denormalised data structure with rules will be something like this (I know data and rules don't live together):

{
  "rules": {
    "public": {
      "people": {
        ".read": true,
        "ivan": {
          "age": 23,
          "location": "Australia"
          "passwordRef": "/non-public/people/ivan/password",
          "underGroundLoverRef": "/non-public/people/ivan/underGroundLover"
        }
      }
    },
    "nonPublic": {
      "people": {
        ".read": false,
        "ivan": {
          ".read": false,
          "password": {
            ".read": if(user === "ivan" || user.group = "admin" || user.group === "ivan's parent")
          },
          "underGroundLover": {
            ".read": if(user !== "ivan's wife")
          }
        }
      }
    }
  }
}

Is there any other more efficient way that I can implement filter? If Firebase can answer me, I'd also want to know why security rule or data fetching have to be all-or-nothing? Wouldn't it be nice if Firebase can filter/hide data base on rules?

Community
  • 1
  • 1
Ivan Wang
  • 8,306
  • 14
  • 44
  • 56
  • 1
    You cannot hide parts of a node. An entire node is either readable by a user or it's not. We can agree that it would be nice if you load partial nodes or use security rules to filter data. But in the end what matters is how it works: a read operation can never return a subset of the location it reads based on security rules. – Frank van Puffelen May 27 '16 at 15:54
  • Ummm I see. Looks like this is the deal breaker for us against using Firebase in production... – Ivan Wang May 28 '16 at 01:19
  • 1
    It is quite common in NoSQL database to model/duplicate your data to match your use-cases. The reason many developers reach incredible scalability with NoSQL solutions is that they embrace these concepts and work within them to reach their needs. To get more comfortable with this approach, I highly recommend reading [NoSQL data modelling](https://highlyscalable.wordpress.com/2012/03/01/nosql-data-modeling-techniques/). – Frank van Puffelen May 28 '16 at 01:48
  • If you're worried about loading joined data, duplicate that data and/or read http://stackoverflow.com/questions/35931526/speed-up-fetching-posts-for-my-social-network-app-by-using-query-instead-of-obse/35932786#35932786 – Frank van Puffelen May 28 '16 at 01:52
  • Yes, I see what you mean to minimise the the n+1 effect. That is not bad until the app has reached to a certain scale I guess. Actually, may I suggest a feature to Firebase? If Firebase can support `include` as in SQL, `populate` as in MongoDb or even just general `batch`, my n+1 problem can be cleanly solved from FIrebase's side with the sample structure that I showed. – Ivan Wang May 28 '16 at 02:06

1 Answers1

6

A possible solution is to simply keep duplicate data. Common practice in NoSQL databases and disk space is cheap...

For all users that want to know about Ivan:

"people_public": {
  "ivan": {
    "age": 23,
    "location": "Australia"
  }
}

and the private node just for Ivan himself

"people_private": {
  "ivan": {
    "age": 23,
    "location": "Australia"
    "password": "123",
    "underGroundLover": "JLo"
  }
}

Public users would generally just be looking it Ivan's data, not modifying it so if Ivan decided to move to Cleveland, he would be the one updating it, so update both nodes with a multi-location update.

This also really simplifies the security rules as users can only access their own nodes in the people_private node.

Jay
  • 34,438
  • 18
  • 52
  • 81
  • Great answer Jay! I wish I could separate extra-upvote the paragraph about how this simplifies your security rules. :-) – Frank van Puffelen May 27 '16 at 20:03
  • If I understand you correctly, you are going to put `.read` rule logic under `people_private/ivan` node instead of its individual sub-nodes, which means this structure has a lack of flexibility to manage attribute permissions per user group (such as admin group, Ivan's parent group and Ivan's wife group). – Ivan Wang May 28 '16 at 01:11
  • Yes.. and no! Yes you could add a read rule to the people_private that only allows ivan to modify their own node. But, a better way would be to create a node of /ivans_peeps that has the uid: true of the users that are allowed to modify the ivan node. Then your rule could verify the user is auth'd and that their uid appears in the /ivans_peeps node. This could be an administrator node or a variety of others. @FrankvanPuffelen may have another suggestion. – Jay May 28 '16 at 12:46