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

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

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.

Trouble implementing firebase rules

I'm having issues reading and writing data from my database on the client (my iOS app) using the following database rules:
// Checks auth uid equals database node uid
// In other words, the User can only access their own data
{
"rules": {
"posts": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
However, I have no issues reading and writing my data when using the following rule:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
My goal is to have each user only have the ability to read/write their own data. Any suggestions/help would be appreciated.
EDIT:
When attempting to post I use the following (iOS):
let key = ref?.childByAutoId().key
let post = ["uid": key,
"title": titleField.text,
"description": descField.text]
ref?.child(key!).setValue(post)
When I want to retrieve those data entries, currently I am attempting to retrieve the data entries by looking at the reference point ("task") (in iOS, my database reference is the following):
ref = Database.database().reference().child("task")
ref.observe(.childAdded, with: { (snapshot) in
print(snapshot)
guard let dictionary = snapshot.value as? [String : AnyObject]
else {
return
There are a couple things going on here.
First as Doug answered, your rules have to match your query.
Second, when using childByAutoId() you are creating a random key. Instead you should be using the UID of the logged in user.
And third when reading from the database you have to make sure to read from the location where you have placed your rules. Currently you are trying to read the entire list were there are no rules defined. (When no rules are defined Firebase defaults to false) Instead you should read the child of the list.
You can also take a look at my answer here for some more explenation and links to relevant docs.
Your rules don't match your queries. Your query is accessing documents at a node called "task", but your rules are protecting a node called "posts". You should edit your rules to match the queries you intend to protect.

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 realtime db security rule to allow specific users

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

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.

Resources