4

Update / Answer Feb 2018

It seems Query-based rules are currently unable to afford this level of security / elegance to the realtimeDB structure. Something like this would require nested sorting, variable 'key' indexes (as with the current "indexOn": ".value", or some other magic yet to be dreamed up by the firebase team.

In the meantime I can definitely recommend reading up on query-based rules:


Original Q: Given a list of firebase realtime-db nodes, each with a named list of groups, and a group I would like to lookup - I am looking to restrict access via query-based rules so that only nodes with the given group are returned. Everything else should be considered private data.

E.g DB:

[lookup]: {
  id1: {
    groups: {
      randomgroup1: true
    },
  },
  id2: {
    groups: {
      randomgroup1: true,
      randomgroup2: true
    },
  }
}

Realtime DB Rules:

"lookup": {
  ".read": "query.orderByChild != null && query.equalTo != null",
  "$uid": {
    ".indexOn": "groups"
  }
}

And valid request/query:

const $group = 'randomgroup2';
firebase.ref('lookup').orderByChild(`groups/$group`).equalTo(true).once('value')

The above correctly returns id2: { groups: { randomgroup1: true, randomgroup2: true }} HOWEVER the entire [lookup] node is sent to the client to be filtered due to the lack of an index on the group names, i.e. the data is not secure.

How best to do this so to retain security? I am open to changing the structure of the nodes, or updating the security rules.

Note: this is entirely possible with the tried and tested many-to-many relationship setup (i.e. firebase brute-force duplicate databasing 101), it is similarly possible (and secure) with the technique above where only 1 group is required per record.

som
  • 2,023
  • 30
  • 37

1 Answers1

1

Your current data structure is well suited to look up the groups for a given id.

But to look up the ids for a given group you will need to execute a query, as you're trying to do.

For the query to be executed on the server, you need to have an index defined on the field you order on, so groups/$group. That means you will need to define an index on each groups/randomgroup1, groups/randomgroup2, etc. This is not feasible.

That's why you'll want to add another node to your data structure that contains precisely the information you want to look up: the ids for each randomgroup:

[lookup2]: {
  randomgroup1: {
    id1: true
  },
  randomgroup2: {
    id1: true,
    id2: true
  }

Now with this structure you can also directly look up the ids for a given group.

For more on such bidirectional lookups, see:

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • As usual thanks for the insight Frank. I guess the intention here was to utilise the new query-based rules in order to simplify the structure of my DB, which is to say I realise there is a brute force approach but I was looking for elegance. E.g. you can `"indexOn": ".value"` for `orderByValue` queries - is there a way to structure the data so `orderByValue` could be used in place of `orderByChild`? Trying to push the envelope here with the new tech. – som Feb 27 '18 at 04:34
  • There is no way to define a single index that takes on multiple values for each child node. That's how I remember what's possible and what isn't. – Frank van Puffelen Feb 27 '18 at 04:36
  • Cool, makes sense. I guess bruteforce it is .. or only allowing a single group – som Feb 27 '18 at 05:11