Firebase Security

INTRO

Folks normally get to firebase security after they have already dived in and half created their app. This is the wrong approach. Security needs to be considered from the outset, sort that out first, then the rest will follow...

Why do we need to secure our Firebase data:

  1. To ensure that we protect our users, who may be supplying personal information. We have a legal duty to do so, in most countries in the world. In the UK this is governed by the General Data Protection Regulations.

  2. We want to keep our data from being lost. If a malicious user gets a hold of your firebase URL, a simple script can completely erase your entire project. There is no recovery option, once it is gone, it is gone.

  3. To provide some granularity over what users can see in the data, what and where they can write to (if at all).


Firebase provides for all forms of fancy and conditional rules that can be applied to your data, my aim here is to just set out the main three or four basic sets of rules to get you going.

You can refer to the Firebase Documentation on Securing your Data. I have attempted to keep this as simple as possible, and, under the defining "rules", I have always set a ProjectBucket - this can be any path, sometimes several layers deep, to the data.

Firebase Rules are held and edited in Firebase via the Firebase Console

Firebase Realtime Database Rules

  1. Read and Write

    1. This is the starting point, anyone can read and write data to and from the project, useful for development purposes only. If the two "trues" are set to false, then the only way to access or edit data is through the Firebase Console.

{

"rules": {

"<ProjectBucket>": {

".read" : true,

".write": true

}

}

}

  1. Read and Write for Authenticated Users

    1. The rules here provide for the same as 1 above, however all users must be authenticated to the project, e.g. they must have signed in / logged in (perhaps been verified as users) in order to access and edit all the data

{

"rules": {

"<ProjectBucket>": {

".read": "auth.uid != null"

".write": "auth.uid != null"

}

}

}

  1. Read All, but Write only to a User's Area

    1. Here, we allow anyone to read data, but only authenticated content owners can make changes to their data. You will see here that an additional level of "uid" has been added. This uses the uid or localId or the user (you see this on the Authentication page). When adding data this "uid" has to be included in the "path".

"rules": {

"<ProjectBucket>": {

"$uid": {

".read": true,

// or ".read": "auth.uid != null" for only authenticated users

".write": "auth.uid == $uid"

}

}

}

}

  1. Read and Write only to a User's Area

    1. This provides an authenticated user access to just their own content. They can read and write in their own protected area, again using the "uid" as the marker for their data

{

"rules": {

"<ProjectBucket>": {

"$uid": {

".read": "$uid === auth.uid",

".write": "$uid === auth.uid"

}

}

}

}


Once development is done, you should, as a bare minimum, be using rules as in 2. That said, this will mean you will need to organise authentication for your users!


Here is where you edit the Realtime Database rules on the console:

Firebase Storage Rules

  1. Read and Write

    1. This again is the open setting for the storage area, and again accessing files placed in storage is very easy if you have the storage ID and file name, because the url is otherwise the same. Again, to be used for development purposes. The use of "{bucket}" allows for any storage bucket in your projects. You can replace this with your application ID: e.g. "{myProject.appspot.com}". As with the realtime database, if you set both rules to false, only you have access through the console.

rules_version = '2';

service firebase.storage {

match /b/{bucket}/o {

match /{allPaths=**} {

allow read, write: if true;

}

}

}

    1. Read and Write for All Authenticated Users

      1. Provides read and write access to Firebase Storage to any authenticated user, everyone will need to authenticate to access files

service firebase.storage {

match /b/{bucket}/o {

match /{allPaths=**} {

allow read, write: if request.auth != null;

}

}

}

    1. Mixed - Anyone can Read but only Authenticated Users can Write

      1. This can be useful to control provision of user content to authenticated users, but make that content accessible to all

rules_version = '2';

service firebase.storage {

match /b/{bucket}/o {

match /{allPaths=**} {

allow read: if true

allow write: if request.auth != null;

}

}

}


As a minimum, once development is finished, you should be using rules as in 3, but if you need to protect the files from anyone viewing, then use rules in 2.


Here is where you edit Storage rules on the console:

In App Inventor

We will also need to apply some rules to development and production in App Inventor, because here we will be using the access keys in order to complete Firebase requests. Just as you see when using the experimental component or firebase extensions we will need to use the "API key", the "Firebase URL", and the "Storage App ID". These can all be found on the project settings pages for the database and storage elements. We need to keep these keys secure and away from prying eyes.

  • First line of defence is to use the obfuscated text block

  • Second line of defence is to use an encryption algorithm in the app

  • Third line of defence is to not store these items on the app at all, and to have them in encrypted format on a server, to call down to the app on use, and decrypt in memory. This does require a network connection which may not always be practical though....

  • Use what works best for you and is suitable for your app. Compiled apps are becoming increasing targets for hacking. If there is nothing there to hack (OK, nothing is "unhackable"...), then you are doing the best you can.

  • You should also have a data backup strategy in place if you cannot afford to lose the data.

  • Authenticated user security is well controlled by Firebase authentication. When a user authenticates (logs in), they are provided with an ID token that has a working life of one hour. When that expires, they must log in again. (You can automate this to some extent using a timer and the refresh token)


In Closing

Ok, so now we know all about Firebase rules, why they are important, and when to use them.

We will now move on to PART II, which somewhat perversely, sets up a demo using Firebase with no rules! ... tiny steps ....