0
votes

I have a question for my own sanity. Below is one portion of my firebase rules

{
  "rules": {
      ".read": "auth != null",
      ".write" : false,
      "users": {
           "$uid": {
               ".read": "auth != null && auth.uid == $uid", 
               ".write": "auth != null && auth.uid == $uid",
               "tokens": {
                   ".write": "(newData.val() < data.val())"
               }
           }
      },
      ...

If I understand correctly the rules state that:

  • ALL users must be auth'ed in order to read ANY node
  • ALL user can NOT write to any nodes
  • Specific to the User node:
  • In order to read from your own data, you need to be auth'ed and you can only read your own node
  • In order to write to your own user data, you must be auth'ed and you can only write to your own node
  • The user/token node can only be decremented and never increased by any user

Can someone confirm my assumptions/understandings reading Firebase security rules documentation.

Also does anyone have any good articles or helpful tips on using the simulator!?

1

1 Answers

2
votes

An important concept with the security rules is that read/write rules "cascade" down the tree. This is discussed briefly in the documentation. That means that as you read your rules from top to bottom, the first rule that grants access takes precedence over any rules specified below it on children of that location.

Addressing each of your items:

  • ALL users must be auth'ed in order to read ANY node (YES)
  • ALL user can NOT write to any nodes (non-auth'ed users can NOT write to any nodes)
  • Specific to the User node:
  • In order to read from your own data, you need to be auth'ed and you can only read your own node (YES)
  • In order to write to your own user data, you must be auth'ed and you can only write to your own node (YES)
  • The user/token node can only be decremented and never increased by any user (see below)

In your current rules, the check for smaller token is not effective because the prior rule granting write access to an auth'ed user overrides it. You also need to address the case where there is no existing token value. My suggestion for fixing that is to use a .validate rule. The documentation recommends:

Used once a .write rule has granted access, to ensure that the data being written conforms to a specific schema.

{
  "rules": {
    ".read": "auth != null",
    ".write": false,
    "users": {
      "$uid": {
        ".read": "auth.uid == $uid",
        ".write": "auth.uid == $uid",
        "tokens": {
          ".validate": "!data.exists() || (newData.val() < data.val())"
        }
      }
    }
  }
}

As for the Simulator, I don't know of any user guide, but have managed to learn how to use it by experimentation. It's a very effective tool for understand the rules.

Here are a few cases of using the Simulator:

When you open the Simulator, Authenticated is off, which simulates a non-authenticated user. To simulate a read, click on the read button, enter a location: e.g. /users/xyz/tokens, and click on Run. You will see a red X on the lines of the rules that forbid that operation. To simulate an authenticated read, click on the Authenticated button and, for convenience, enter a simple user UID, like "Frank". Now enter location /users/Frank/tokens, click on Run and observe that the read succeeds.

You can do similar tests for writing, entering a location, auth settings and value.