Saturday, October 8, 2022

Firebase Security Rules - Part1

Firebase Security Rules leverage extensible, flexible configuration languages to define what data your users can access for Realtime Database, Cloud Firestore, and Cloud Storage. Firebase Realtime Database Rules leverage JSON in rule definitions, while Cloud Firestore Security Rules and Firebase Security Rules for Cloud Storage leverage a unique language built to accommodate more complex rules-specific structures.

Firebase Security Rules work by matching a pattern against database paths, and then applying custom conditions to allow access to data at those paths. All Rules across Firebase products have a path-matching component and a conditional statement allowing read or write access. You must define Rules for each Firebase product you use in your app.

{

  "rules": {

    "<<path>>": {

    // Allow the request if the condition for each method is true.

      ".read": <<condition>>,

      ".write": <<condition>>,

      ".validate": <<condition>>

    }

  }

}

Rules are applied as OR statements, not AND statements. Consequently, if multiple rules match a path, and any of the matched conditions grants access, Rules grant access to the data at that path. Therefore, if a broad rule grants access to data, you can't restrict with a more specific rule. You can, however, avoid this problem by making sure your Rules don't overlap too much. Firebase Security Rules flag overlaps in your matched paths as compiler warnings.


{

    "messages": {

      "message0": {

        "content": "Hello",

        "timestamp": 1405704370369

      },

      "message1": {

        "content": "Goodbye",

        "timestamp": 1405704395231

      },

      ...

    }

  }

For a document like the above, below is the rule JSON for firebase database 

{

    "rules": {

      "messages": {

        "$message": {

          // only messages from the last ten minutes can be read

          ".read": "data.child('timestamp').val() > (now - 600000)",


          // new messages must have a string content and a number timestamp

          ".validate": "newData.hasChildren(['content', 'timestamp']) &&

                        newData.child('content').isString() &&

                        newData.child('timestamp').isNumber()"

        }

      }

    }

  }


As the example above shows, Realtime Database Rules support a $location variable to match path segments. Use the $ prefix in front of your path segment to match your rule to any child nodes along the path. Here $message is the location key 

You can also use the $variable in parallel with constant path names.

{

    "rules": {

      "widget": {

        // a widget can have a title or color attribute

        "title": { ".validate": true },

        "color": { ".validate": true },


        // but no other child paths are allowed

        // in this case, $other means any key excluding "title" and "color"

        "$other": { ".validate": false }

      }

    }

  }

Pre-defined variables

now => The current time in milliseconds since Linux epoch. This works particularly well for validating timestamps created with the SDK's firebase.database.ServerValue.TIMESTAMP.

root => A RuleDataSnapshot representing the root path in the Firebase database as it exists before the attempted operation.

newData => A RuleDataSnapshot representing the data as it would exist after the attempted operation. It includes the new data being written and existing data.

data => A RuleDataSnapshot representing the data as it existed before the attempted operation.

$ variables => A wildcard path used to represent ids and dynamic child keys.

auth => Represents an authenticated user's token payload.


These variables can be used anywhere in your rules. For example, the security rules below ensure that data written to the /foo/ node must be a string less than 100 characters:

{

  "rules": {

    "foo": {

      // /foo is readable by the world

      ".read": true,


      // /foo is writable by the world

      ".write": true,


      // data written to /foo must be a string less than 100 characters

      ".validate": "newData.isString() && newData.val().length < 100"

    }

  }

}


references:

https://firebase.google.com/docs/rules/rules-behavior


No comments:

Post a Comment