firebase realtime db security rule to allow specific users - firebase

my current firebase realtime security rules are like below
{
"rules": {
"users": {
".read" : true,
".indexOn": ["email"],
"$user_id": {
".read": true,
".write": "auth != null && $user_id === auth.uid"
}
}
}
}
they translates as only the authenticated user can write the data to his own node under users/
However, we have admin users who should be able to modify the data of non admin users.
The way we identify admin users are a user property isAdmin which is true for admin users. so the sample data with a admin and non admin user looks like below
{
"users": {
"kldjjfjf" : {
"name": "vik", "isAdmin": true
},
"lfllfomr": {
"name": "neeti", "isAdmin": false
}
}
Please advise what is the best practice to handle this kind of usecases? doing a .write true will solve it but then it will make it open to anyone to modify anyone's data.

The simplest ways I've found to allow Administrative access is to:
Use a custom claim for admins
Use a whitelist of admin UIDs
Use a custom claim for admins
You can add custom claims to Firebase Authentication user profiles with the Admin SDK. Claims are custom key/value pairs that you determine the meaning of yourself. The first example from the documentation shows setting a claim called admin to true, for example with the Admin SDK for Node.js:
admin.auth().setCustomUserClaims(uid, {admin: true}).then(() => {
// The new custom claims will propagate to the user's ID token the
// next time a new one is issued.
});
Once a custom claim is set, it is transported to the client when it signs in, and is also available in security rules. You can check the above with:
".write": "auth != null && ($user_id === auth.uid || auth.token.admin === true)"
Use a whitelist of admin UIDs
A simple alternative is to store a list of UIDs in your database of users with specific privileges. For example, you could have a top-level Admins list:
Admins
uidOfVik: true
uidOfPuf: true
The above means that you and me are admins. You then check for those in the security rules:
".write": "auth != null && ($user_id === auth.uid || root.child('Admins').child(auth.uid).exists())"

Here's an alternative:
Firebase security rules only apply to clients connecting normally to the application.
If you have your own back end (I can't assume that, because Firebase is made for Serverless computing) then it can connect to the application with the admin SDK, which bypasses the security rules.
Alternatively, you can make a separate application for your admin users, that will connect to firebase using the admin SDK.
More information: Firebase Documentation - Firebase Admin SDK

Related

Firebase rules warning - any user can read your entire database [duplicate]

I recently received an email from firebase telling me that my realtime database has insecure rules. These are the rules that I have set:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
Is this not a secure rule?
Email/Password is the only sign-in method that I have enabled.
firebaser here
I'm sorry if the email wasn't very explicit about what isn't secure about those rules. Securing your user's data is a crucial step for any app that you make available, so I'll try to explain a bit more about how that works below.
The (default) rules you have allow anyone who is signed in to your back-end full read/write access to the entire database. This is only a very basic layer of security.
On the one hand this is more secure than just granting everyone access to your database, at least they have to be signed in.
On the other hand, if you enable any auth provider in Firebase Authentication, anyone can sign in to your back-end, even without using your app. Depending on the provider, this can be as easy as running a bit of JavaScript in your browser's developer console. And once they are signed in, they can read and write anything in your database. This means they can delete all data with a simple command like firebase.database().ref().delete().
To make the data access more secure, you'll want to more tightly control what each signed-in user can do. For example, say that you keep a profile with information about each user under /users. You might want to allow all users to access these profiles, but you definitely want users to only be allowed to modify their own data. You can secure this with these rules:
{
"rules": {
"users": {
".read": true,
"$user_id": {
// grants write access to the owner of this user account
// whose uid must exactly match the key ($user_id)
".write": "$user_id === auth.uid"
}
}
}
}
With these rules, everyone (even non-authenticated users) can read all profiles. But each profile can only be modified by the user whose profile it is. For more on this, see the Firebase documentation on securing user data.
In addition to ensuring that all access to data is authorized, you'll also want to ensure that all data stored is valid to whatever rules you have for you app. For example, say that you want to store two properties for a user: their name, and their age (just for the sake of the example, in reality you'd probably store their date-of-birth instead). So you could store this as something like:
"users": {
"uidOfPuf": {
"name": "Frank van Puffelen",
"age": 48
}
}
To ensure only this data can be written, you can use this rules:
{
"rules": {
"users": {
".read": true,
"$user_id": {
".write": "$user_id === auth.uid",
".validate": "data.hasChildren('name', 'age')",
"name": {
".validate": "data.isString()",
},
"age: {
".validate": "data.isNumber()",
},
"$other: {
".validate": false
}
}
}
}
}
These rules ensure that each user profile has a name and age property with a string and numeric value respectively. If someone tries to write any additional properties, the write is rejected.
Above is a quick primer on how to think about securing your (user's) data. I recommend that you check out the Firebase security documentation (and the embedded video) for more.
Update: since May 2021 you can also use Firebase App Check to restrict access to calls just coming from your web site or app. This is another, quick way to reduce the abuse of your database. This approach is not foolproof though, so you'll want to combine App Check for broad protected, with the security rules for fine-grained control.
You can also mute alerts by visiting the link at the bottom of the email.
https://console.firebase.google.com/subscriptions/project/<YOUR_PROJECT_NAME>
I changed rules
{
"rules": {
"users": {
".read": true,
"$user_id": {
// grants write access to the owner of this user account
// whose uid must exactly match the key ($user_id)
".write": "$user_id === auth.uid"
}
}
}
}
But after that page not working.

Firebase Auth with Firestore [duplicate]

I recently received an email from firebase telling me that my realtime database has insecure rules. These are the rules that I have set:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
Is this not a secure rule?
Email/Password is the only sign-in method that I have enabled.
firebaser here
I'm sorry if the email wasn't very explicit about what isn't secure about those rules. Securing your user's data is a crucial step for any app that you make available, so I'll try to explain a bit more about how that works below.
The (default) rules you have allow anyone who is signed in to your back-end full read/write access to the entire database. This is only a very basic layer of security.
On the one hand this is more secure than just granting everyone access to your database, at least they have to be signed in.
On the other hand, if you enable any auth provider in Firebase Authentication, anyone can sign in to your back-end, even without using your app. Depending on the provider, this can be as easy as running a bit of JavaScript in your browser's developer console. And once they are signed in, they can read and write anything in your database. This means they can delete all data with a simple command like firebase.database().ref().delete().
To make the data access more secure, you'll want to more tightly control what each signed-in user can do. For example, say that you keep a profile with information about each user under /users. You might want to allow all users to access these profiles, but you definitely want users to only be allowed to modify their own data. You can secure this with these rules:
{
"rules": {
"users": {
".read": true,
"$user_id": {
// grants write access to the owner of this user account
// whose uid must exactly match the key ($user_id)
".write": "$user_id === auth.uid"
}
}
}
}
With these rules, everyone (even non-authenticated users) can read all profiles. But each profile can only be modified by the user whose profile it is. For more on this, see the Firebase documentation on securing user data.
In addition to ensuring that all access to data is authorized, you'll also want to ensure that all data stored is valid to whatever rules you have for you app. For example, say that you want to store two properties for a user: their name, and their age (just for the sake of the example, in reality you'd probably store their date-of-birth instead). So you could store this as something like:
"users": {
"uidOfPuf": {
"name": "Frank van Puffelen",
"age": 48
}
}
To ensure only this data can be written, you can use this rules:
{
"rules": {
"users": {
".read": true,
"$user_id": {
".write": "$user_id === auth.uid",
".validate": "data.hasChildren('name', 'age')",
"name": {
".validate": "data.isString()",
},
"age: {
".validate": "data.isNumber()",
},
"$other: {
".validate": false
}
}
}
}
}
These rules ensure that each user profile has a name and age property with a string and numeric value respectively. If someone tries to write any additional properties, the write is rejected.
Above is a quick primer on how to think about securing your (user's) data. I recommend that you check out the Firebase security documentation (and the embedded video) for more.
Update: since May 2021 you can also use Firebase App Check to restrict access to calls just coming from your web site or app. This is another, quick way to reduce the abuse of your database. This approach is not foolproof though, so you'll want to combine App Check for broad protected, with the security rules for fine-grained control.
You can also mute alerts by visiting the link at the bottom of the email.
https://console.firebase.google.com/subscriptions/project/<YOUR_PROJECT_NAME>
I changed rules
{
"rules": {
"users": {
".read": true,
"$user_id": {
// grants write access to the owner of this user account
// whose uid must exactly match the key ($user_id)
".write": "$user_id === auth.uid"
}
}
}
}
But after that page not working.

Firebase email saying my realtime database has insecure rules

I recently received an email from firebase telling me that my realtime database has insecure rules. These are the rules that I have set:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
Is this not a secure rule?
Email/Password is the only sign-in method that I have enabled.
firebaser here
I'm sorry if the email wasn't very explicit about what isn't secure about those rules. Securing your user's data is a crucial step for any app that you make available, so I'll try to explain a bit more about how that works below.
The (default) rules you have allow anyone who is signed in to your back-end full read/write access to the entire database. This is only a very basic layer of security.
On the one hand this is more secure than just granting everyone access to your database, at least they have to be signed in.
On the other hand, if you enable any auth provider in Firebase Authentication, anyone can sign in to your back-end, even without using your app. Depending on the provider, this can be as easy as running a bit of JavaScript in your browser's developer console. And once they are signed in, they can read and write anything in your database. This means they can delete all data with a simple command like firebase.database().ref().delete().
To make the data access more secure, you'll want to more tightly control what each signed-in user can do. For example, say that you keep a profile with information about each user under /users. You might want to allow all users to access these profiles, but you definitely want users to only be allowed to modify their own data. You can secure this with these rules:
{
"rules": {
"users": {
".read": true,
"$user_id": {
// grants write access to the owner of this user account
// whose uid must exactly match the key ($user_id)
".write": "$user_id === auth.uid"
}
}
}
}
With these rules, everyone (even non-authenticated users) can read all profiles. But each profile can only be modified by the user whose profile it is. For more on this, see the Firebase documentation on securing user data.
In addition to ensuring that all access to data is authorized, you'll also want to ensure that all data stored is valid to whatever rules you have for you app. For example, say that you want to store two properties for a user: their name, and their age (just for the sake of the example, in reality you'd probably store their date-of-birth instead). So you could store this as something like:
"users": {
"uidOfPuf": {
"name": "Frank van Puffelen",
"age": 48
}
}
To ensure only this data can be written, you can use this rules:
{
"rules": {
"users": {
".read": true,
"$user_id": {
".write": "$user_id === auth.uid",
".validate": "data.hasChildren('name', 'age')",
"name": {
".validate": "data.isString()",
},
"age: {
".validate": "data.isNumber()",
},
"$other: {
".validate": false
}
}
}
}
}
These rules ensure that each user profile has a name and age property with a string and numeric value respectively. If someone tries to write any additional properties, the write is rejected.
Above is a quick primer on how to think about securing your (user's) data. I recommend that you check out the Firebase security documentation (and the embedded video) for more.
Update: since May 2021 you can also use Firebase App Check to restrict access to calls just coming from your web site or app. This is another, quick way to reduce the abuse of your database. This approach is not foolproof though, so you'll want to combine App Check for broad protected, with the security rules for fine-grained control.
You can also mute alerts by visiting the link at the bottom of the email.
https://console.firebase.google.com/subscriptions/project/<YOUR_PROJECT_NAME>
I changed rules
{
"rules": {
"users": {
".read": true,
"$user_id": {
// grants write access to the owner of this user account
// whose uid must exactly match the key ($user_id)
".write": "$user_id === auth.uid"
}
}
}
}
But after that page not working.

Firebase Database rules - Give unauthenticated user access to ONLY read specific path

Say my Firebase Database rules look like this:
"rules": {
".read": "auth != null",
".write": "auth != null"
}
In my app I need to check if a username is already taken, and thus I need to do so before authenticating the user. I am aware that I could do something like this:
"rules": {
".write": "auth != null",
"Users": {
".read": true
}
}
However, if I have understood how the rules work correctly, this will make only the "Users" path readable and by default every other path will be set to ".read": false. My question is therefore how I would make every path readable by an authenticated user, and make an unauthenticated user only able to read data from the path "Users" and nothing else.
Certainly you can make it so one path in the database is readable for unauthenticated users, but I wouldn't recommend it. It's not ideal to allow anyone to read the usernames of all of your users.
One other option is you can create a user first and then have them choose a username once authenticated, but then you'd have to figure out how you wanted to handle users who are authenticated but then exit the app before choosing a username.
A better option is to use Cloud Functions for Firebase with an HTTP trigger, and pass the desired username as part of the request. The request would include a query of the desired username and the response would return whether the username is available or not. It could look something like this:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.uniqueUsername = functions.https.onRequest((req, res) => {
const username = req.query.username
admin.database().ref('users').orderByChild('username').equalTo(username)once('value').then(snap => {
// if the child exists, then the username is taken
if (snap.exists()) {
res.send('username not available');
} else {
res.send('username available');
}
})
}
If you're new to Cloud Functions for Firebase, then check out these resources:
Getting Started with Cloud Functions for Firebase - YouTube
Cloud Functions for Firebase Documentation
Cloud Functions Samples
Timing Cloud Functions for Firebase using an HTTP Trigger and Cron - YouTube

Permission denied with Firebase Database rules

I have the following form of database
Database
users
<UID>
user
<other information>
I am trying to read all my users in admin mode and only allow individual users to access their own information.
I am trying this rule:
"users": {
"$uid": {
".read": "auth != null && (auth.uid == $uid || root.child('users').child(auth.uid).child('user').child('admin').val() == true)",
".write": "auth != null && !newData.child('admin').exists() && (auth.uid == $uid || root.child('users').child(auth.uid).child('user').child('admin').val() == true)"
},
".indexOn": ["userid"]
},
I am doing the following query and I see the following error:
allusers = $firebaseArray(firebaseDataService.root.child('users'));
permission_denied at /users: Client doesn't have permission to access the desired data.
Any idea what I am doing wrong here ?
When you attach a listener to /users, the Firebase server checks whether you have read permission on /users. If not, it rejects the listener.
This is a common source of confusion for developers new to Firebase. Coming from a SQL/relation mindset, we are used to use security to perform (server-side) filtering. In Firebase you cannot use security rules to filter data.
I'll add a few relevant links below for further reading:
rules are not filters in the Firebase documentation
Restricting child/field access with security rules
the Firebase blog post on why denormalizing is normal
an article on airpair about data structuring
a great summary from a while ago on the firebase-talk group

Resources