1

In firebase realtime database our users have a custom claim called premium this claim can have three values LEVEL_1 , LEVEL_2 or REGULAR my database rules are:

    {
  "rules": {
    ".read": "auth.token.admin === true",
    ".write": "auth.token.admin === true",
    "$uid": {
         ".read": "$uid === auth.uid",
         ".write": "$uid === auth.uid",
           "Boxes":{
            "Manual":{
             ".read": "auth.token.premium === 'REGULAR'",
             ".write": "auth.token.premium === 'REGULAR'",
           } 
           }
       },
  }
}

But I want to say if premium value is REGULAR only allow read/write for 5 records and if it is LEVEL_1 only 20 records and for LEVEL_2 access to all records and if we change from LEVEL_1 to REGULAR for example the rules do not remove records and just don't allow write more and allow for read 5 records.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441

2 Answers2

0

Security rules don't have the ability to count anything. They can't limit the number of times data may be read or written.

The alternative is to use a backend you control, and create an endpoint that performs the counting. The endpoint will have to determine how to count the number of allowed read and writes.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • Thanks, I already made a backend API but it's for the web app, the problem is in the mobile app they used firebase codes directly in the app and not using backend API so is it the right way if I get the custom claims from userIdToken and set limits inside the mobile app? also this way the limit only works in the mobile app and if someone get data using firebase functions they can have access to all records without limit – Hadi Faramarzi Dec 30 '19 at 01:50
  • Also I think we can limit number of records: https://firebase.google.com/docs/database/security/securing-data in this example they limited number of messages to last ten minutes – Hadi Faramarzi Dec 30 '19 at 01:58
0

There's a lot going on in your use-case, so I'm going to address the read side first. As far as I can see, you have the following requirements:

  1. REGULAR users can read up to 5 items.
  2. LEVEL_1 users can read up to 20 items.
  3. LEVEL_2 users can read all items.

You can secure this with a combination of queries, and a check on the queries in your security rules. Starting with the query, you apparently want these three queries:

ref.orderByKey().limitToFirst(5)  // REGULAR
ref.orderByKey().limitToFirst(20) // LEVEL_1
ref.orderByKey()                  // LEVEL_2

The exact field/key you order on may not make a difference, but you must order on something as otherwise malicious users can still read more items than they're allowed to by simply ordering on different properties.

Now we can write the rules to allow these queries, and thus disallow other read operations:

"items": {
  ".read": "query.orderByKey && (
            (auth.token.premium === 'REGULAR' && query.limitToFirst <= 5) ||
            (auth.token.premium === 'LEVEL_1' && query.limitToFirst <= 20) ||
            (auth.token.premium === 'LEVEL_2'"
}

For write operations: as Doug said, you can't use the number of nodes in security rules. This means you'll have to limit the number by either storing that count, having named slots, or some other workaround. Kato has written an example of this a few years ago, which shows a basic approach: Limit number of records that can be written to a path (reference other paths in security rules)

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