— javascript, web-development, firebase — 4 min read
Firebase is bit weird in perspective of security at first glance. For instance, when you first add firebase to your app, you get to the below screen and the first thing that should catch your eye is apiKey, its exposed, shouldn't it be somewhere secured.
Thing you should know about this apiKey
in firebase config is, it just identifies your Firebase project on the Google servers. So, its 0.K for it to be exposed. Think of it as a bad name given to a key.
Thinking in security perspective, there are two levels of security available to you,
Firebase encourages to use server side security rules to ensure only authorized users can access the data and rules are designed in such a way that accesses are node-based. If a user has access to parent nodes, that user will be able to access child nodes as well.
These rules control access to file storage and database access, and are enforced on the Firebase servers. So no matter if it's your code, or somebody else's code that uses you configuration data, it can only do what the security rules allow it to do. -- Frank van Puffelen
Firebase rules are nodes-based meaning they sort of look like json key:values. As a general rule, keep your security rules simple. Because if your data is not well structured, rules can get complex. Try not to get into that zone.
In firebase, default rule in Realtime database is Locked mode(deny access to all users). This could be really useful in emergency cases, all you have to do is update the Rules tab in Realtime Database menu option as below,
1{2 "rules": {3 ".read": false,4 ".write": false5 }6}
Below one, you can call it as Development mode(allow access to all users -- No Security)
As said in the warning
Your security rules are defined as public, so anyone can steal, modify, or delete data in your database
Simplest way of upgrading the rule is to set only authenticated users are allowed to do any DML Operations like below,
1{2 "rules": {3 ".read": "auth != null",4 ".write": "auth != null"5 }6}
After updating the rule, its always good to test the rule in the Rules Playground as that seem to be one of the quickest way to test rules and then publish it. Do remember, this rule is OK for development not for production as here all authenticated users have access to all the data to read and write everyone elses data.
Little planning is required from the beginning, that is from the time of Structuring the data as security and data structure are connected in Firebase.
Production can have below types of data,
Here we have three nodes, categories, stash and users
Under the parent nodes, lies the userIDs(UID) as keys as in key:value to the specific user data.
Here you can see/understand how the userID(UID) is tied to the rules
In this application, data is stored under the specific userIDs and by the below rules, we are making sure only that specific user has access to it.
Here .read
is set in such a way, all authenticated users can read any other users data and users can only update their own data
1{2 "rules": {3 "some_path": {4 "$uid": {5 ".read": "auth.uid != null", 6 ".write": "auth.uid == $uid"7 }8 }9 }10}
If you set it as below, it means reading is public.
1".read": true,
This is taking things to next level like
1// Allows moderator to update user posts2{3 "rules": {4 "posts": {5 "$uid": {6 ".write": "root.child('users').child('moderator').val() === true"7 }8 }9 }10}
Things to remember,
Why do you want to do this ? Well, whats possible is, since entire firebase config is avaiable in the web application. Someone can clone your application entirely say from GitHub and have users sign-in from their app instead of yours and start accessing the data as a authentic user or use your users data which they are receiving from your backend and their frontend. Whats happening here is Phishing.
Additionally from setting up rules, you can control the domain which can access your data as well.
Google API key restrictions
Go to Google console 🡪 Select the project
From left side menu select API & Services 🡪 left side menu select Credentials
and you will see something like this.
One of the keys appearing above should match up with the apiKey in firebase config. Click that.
Under Application restrictions
SELECT
HTTP referrers (web sites)
🡪 Once you select Website restrictions
option should appear.
Here you can add the urls and do note, if your domain supports both HTTP and HTTPS, both restrictions must be added separately.
localhost
if you are planning to use the same project in production. Click SAVE. Once you are done with this no other site will be able to use your apiKey. Also do note you cannot do any local development testing as well in this project like localhost:5000
as you have not added that, if you do add, there is a probability that a phisher can use that and that defeats the entire purpose of doing this. See the code snippet below to swap project during testing.
You can go still further as your API still has access to many resources, so you can proceed to isolate to specific resource, you want your API to access by selecting Restrict key in API restrictions. Once you are done you can click SAVE.
Code snippet to swap projects during testing(non tested).
1// Production Firebase configuration2const prod_firebaseConfig = {3 apiKey: "< Production apiKey>",4 authDomain: "< Production keys and urls>",5 databaseURL: "< Production keys and urls>",6 projectId: "< Production keys and urls>",7 storageBucket: "< Production keys and urls>",8 messagingSenderId: "< Production keys and urls>",9 appId: "< Production keys and urls>"10};11
12const dev_firebaseConfig = {13 apiKey: "< Development keys and urls>",14 authDomain: "< Development keys and urls>",15 databaseURL: "< Development keys and urls>",16 projectId: "< Development keys and urls>",17 storageBucket: "< Development keys and urls>",18 messagingSenderId: "< Development keys and urls>",19 appId: "< Development keys and urls>"20};21
22const config = process.env.NODE_ENV === 'production' ? prod_firebaseConfig : dev_firebaseConfig;23
24// Initialize Firebase 25if(!firebase.apps.length){26 firebase.initializeApp(config);27}28
29# When running the program in development30NODE_ENV='dev' node index.js
Do note when saving the files in GitHub, you might get mails from Google or Github for storing apiKey like below and this can be ignored as you know now. apiKey
is just firebase way of finding project on Google servers. Common safeguardig way is to privatize the git repo.
This page will be updated as i come to use more firebase rules feature