accessing email address in firebase rules [duplicate] - firebase

This question already has an answer here:
How can we guarantee that the email saved by the Firebase user is indeed his own email?
(1 answer)
Closed 6 years ago.
I'm using firebase 3.
When writing firebase rules, the auth object only contains the uid and the provider. Is there any way that this could be enhanced to also provide the email address?
The problem that I'm trying to solve is that the owner of the site I'm working on wants to permission users based on their email address, because he won't know their firebase uid up front.
I have seen solutions to this suggesting to persist the user object in firebase (with the email) and then use that as a reference point in the rules.
The problem I can see with that is that if someone knew the email address of a user with full privileges, it would be fairly easy to debug the code, and manipulate the email address prior to saving into firebase, which means it would save their firebase id alongside someone else's email address.
The only way I can see to make this safe is to have the email address provided in the auth object in the firebase rules, which can't be hacked.
Am I missing something?
MORE INFO
The idea is that we can control access to data for a specific location by adding the location name to a user's email address:
A user is created ahead of time manually by the site manager, providing access to a subset of data.
e.g
-users
-user1Email
-locations
-someLocation:true
-someOtherLocation:true
The user authenticates via google. On the client side we can see their email address in auth.user.email
In the rules, I want to do something like
locations : {
"$location": {
".read": "root.hasChild('users/' + auth.email + '/locations/' + $location)",
}
}
I know I need to escape the email address, just trying to keep it simple for now.
I've tested this out in the simulator and it works perfectly if I use a custom provider and provide the email in there, but using google the "auth" in the rule only has uid and provider properties, not email.
The alternative (other than using a custom provider) is to allow the user to create their account first, and then the locations are added to each user using their uid as the key rather than their email address, but the owner wants to be able to set it up ahead of time so that the first time they log in it words straight away.

Firebase team is still working to provide the email in the auth object and you can find it with some limitations using auth.token.email in your rules. Please take a look in this post to get more details.
If the current firebase solution doesn't handle all your needs there is some options to workaround.
Since you want to keep your current /users structure you could, whenever registering a new user, link the user uid to the corresponding email in a new branch /user_emails that will simply store $uid: email. Then your rules will look like the following.
"user_emails": {
"$uid": {
".write": "auth.uid == $uid",
".validate": "!root.child('Users').hasChild(newData.val())"
}
},
"locations": {
"$location": {
".read": "root.hasChild('users/' + root.child('user_emails').child(auth.uid).val() + '/locations/' + $location)"
}
}
Keep in mind that you will need to enhance them to ensure that only the right users will be able to edit this new user_emails branch.

Related

Setting Firebase Firestore to only allow read/write from a single Unity App

I've been looking for this answer for a while and honestly there isn't a lot of Firebase using Unity tutorials out that that gives a definitive answer.
I'm using Firestore as a database for an Unity app. My goal is to only allow that app to write to/read from that database. There is no user login, as the app has no use for it. Everything is working already as far as the reading and writing.
My first question is, do I even need Firebase Authentication for this? Or can the app only read/write if it has the associated GoogleServices.json (android) and PList (iOS) files in when it was built? I don't want unauthorized users to access my databse, and i'm unsure how secure just having the json and plist files are.
My second question is this. I have 2 data nodes in the database, one for reading and the other for writing to the general user of the app. I know how to set up the rules so that's the case. But I do want special execution, say I have a personal app that should be able to read the otherwise write-only node, and write to the otherwise read-only node.
Would I need Firebase Authentication then? I assume I have to make a read exception to use Authentication in the security rules.
Thanks in advance for your help.
Question1:
If you do not want unauthorized access to your database, you do need Firebase Auth. Luckily, Firebase Auth has a feature for people like you who don't need to have people log in to your app. It's called Anonymous Authentication, and it essentially works by you signing in users in the back ground without your app's user knowing it. With this, you can restrict database access so that a certain user would not be able to override someone else's data. You can read more about Anonymous Authentication with Unity here.
Question2:
I don't know if the situation you are describing like a admin case, where you as an admin of the app should be able to read/write to the database where normal users should not be allowed, but if that is the case you may use "Custom Claims". With custom claims, you are adding a special key-value pair to your auth token to then use it in security rules. You can read more about custom claims here.
thank you for the quick reply. I got the anonymous sign-in to work, and I think I set up the rules correctly.
I have a document in Firestore called 'organizations', and I want the any user that is signed-in to be able to read it and everything below it, but only write if he's user id is administrator. From the Firestore docs, I think I should set the rules like this:
match /databases/{database}/documents
{
match /organizations/{organization=**}
{
allow read: if request.auth != null;
allow write: if request.auth.uid == "administrator";
}
}
I have a function that runs at the beginning of the app that signs the user in anonymously, which I can confirm works since I can read the user when the task is completed.
However, something isn't working right in the rules.
The app can read the Firestore node whether or not I'm signed in or not. I can comment out the sign-in function, and it will still read the "organization" node. I'm not sure if signing in anonymously does anything at all. Maybe I'm signing in wrong?
Here is my sign-in function:
public async Task SignInAnon()
{
await FirestoreController.firebaseAuth.SignInAnonymouslyAsync().ContinueWith(task =>
{
if (task.IsCanceled)
{
Debug.LogError("SignInAnonymouslyAsync was canceled.");
return;
}
if (task.IsFaulted)
{
Debug.LogError("SignInAnonymouslyAsync encountered an error: " + task.Exception);
return;
}
GameManager.anonUser = task.Result;
Debug.Log("Firebase Signed-In as: " + GameManager.anonUser.UserId);
});
}
anonUser is a static variable initiated elsewhere in the code. Or can I not doing it this way?
EDIT: I'm an idiot. I signed in once and I didn't bother to sign the user out, so I'm treated as signed in even if I comment out the code. :P

Firebase Web Authentication - Administrator Approval for New Accounts

I've got the Firebase Web Authentication pretty much setup and working for oAuth as well as local username/pwds (email addresses).
My question is: Does anyone have an idea as to how to introduce an additional step in there such that new accounts must be approved by a site administrator prior to being fully validated? I was thinking of tweaking/utilizing the user.emailVerified property but I'm thinking that won't work for oAuth users.
Is there an easy way to do this - to add an admin approval step? Or, is there a property in the Firebase Authentication subsystem that I could easily toggle?
Creating a user via Firebase Authentication only provides them with a unique user id. This doesn't allow them any access to your apps or "register" them in any way. That's entirely your purview. It's nothing more than a map of unique credentials (e.g. Facebook IDs or email/password hashes) to unique Firebase IDs.
You can "register" users by having any access privileges you want, and any workflow to get the user added into your Database (or any other appropriate mechanism).
Assuming database, you would write the user profile/meta data into a path, such as /users/$uid, and base your security rules on whether /users/<user id> exists.
To enforce admin approval, the simplest answer would be to maintain a separate path, such as /registered/<user id>/true that's only accessible by admins (and of course by security rules).
Now you can write rules like the following:
{
"...some path...": {
".read": "root.child("registered/" + auth.uid).val() === true"
}
}
Essentially enforcing a registration process.

Firebase Realtime Database: What's the right security rule for a landing page?

My landing page is a coming soon page with Call to Action of subscribing which takes in name, email address etc from the user. The user need not be authenticated to subscribe. He can be any random person who visits this page. I feel the rule should be ".read": false, ".write": true. But Google warns me saying write:true will allow anyone to write to the database even people who do not use the app.
I feel that this is only natural until I put a CAPTCHA or something. How are such issues tackled(spam prevention in subscription or coming soon pages which have forms)?
What you could do to prevent abuse only using security rules (it will not prevent all sorts of spam, for that you should go into captchas and other solutions), you could setup e-mail authentication on Firebase and request e-mail confirmation. Go under Authentication > Sign-in methods > Enable e-mail.
When you save the user e-mail and username on your database, you can create a "users" node in your database and save it under the user id Firebase assigns to the user.
(0TTUf... is the id assigned by Firebase)
Firebase will request a password, as you don't need users to be subscribed and you just need to keep their e-mail and password, just assign a mock password to all users.
It would look like this:
As you're just capturing e-mail and name for yourself and you don't need users to be authenticated, I don't see why you would give users write or read permissions. Just do the logic within your program to save this data.
Then your rules would look like this:
{
"rules": {
".read": false,
".write": false
}
}
No user is allowed to read or write to your database as you're managing it yourself.
Summing it up: Request name and e-mail, assign a password, send this data to
Firebase as a new user signing in, save e-mail and name under
/users/$user_id

How do I modify the user properties managed by FirebaseSimpleLogin?

It seems like the only thing that can be changed is the password (via auth.changePassword()). How do I let a user change their email address or display name?
The firebase Auth object is pretty simple but it will provide you the user id generated when the user authenticates to your system. You would then take this user id and map it to a Users location where you can store additional information such as display name.
For example, after the user has authenticated and you have your auth object with id value, you could do:
new Firebase('https://your_fb_url.firebase.io').child('users/'+id).set({email: email, name: name}, function(err) {})
You'd want to have read/write rules setup on that location to only allow the authenticated user to see & make changes. Something like:
{
"rules": {
"users": {
"$user": {
".read": "$user == auth.uid",
".write": "$user == auth.uid",
}
}
}
}
6/12/2015 - UPDATE - Below is Outdated
As for changing the actual login e-mail (for Firebase Simple Login Web), that I'm not so sure about. I know they provide a change password method but I haven't seen any documentation about a change login/email method.
The underlying code for firebase simple password doesn't appear to include any methods for changing the login e-mail address associated with the account. The changePassword method eventually performs a jsonp call out to /auth/firebase/update with the email, old password, and new password.
I'd hate to suggest using a combination of removeUser/createUser to remove the old account, create a new account, and update any user id associations you have you in your app - but I don't see a straightforward "changeEmail" method. The remove/create route would require the user to enter their password again - though that's a pretty common practice for updating logins these days anyway.
6/12/2015 - UPDATE - New API
Firebase has moved away from Firebase Simple Login as a separate module and now the core Firebase 2.x library has authentication related methods baked in. Including a method to change the e-mail account used for the authWithPassword methods.
See updated 2.x docs for changeEmail()

Securing Firebase CRUD operations with users

Due to the thin AngularFire documentation and the differences between it and the default web documentation for Firebase, I'm a little lost on how best to secure Create, Read, Update, and Delete operations with users.
In short, say I have an application that manages stores. Users can be owners of the stores or patrons. Owners should read and edit their own stores in their view and patrons should read all but edit no stores in their view.
I'm concerned about the security of suggested methods by Firebase docs such as
So for example, we could have a rule like the following to allow users
to create comments as long as they store their user id with the
comment:
{
"rules": {
".read": true,
"$comment": {
".write": "!data.exists() && newData.child('user_id').val() == auth.id"
}
}
}
To me, this means that I could hack my application's data by simply passing in my victim's user id when I want to post a comment as them. Am I wrong?
I've read the security documentation thoroughly, several times. I think I need further explanation here. Identifying by a client-exposed parameter is the only method I can find so far.
In the example shown here, auth refers to the authenticated user's token data. This is a special variable set by Firebase during auth() events, and thus not something you could hack at the client. In other words, you would only be able to write a comment if you set the user_id value to your own account id.
The contents of the auth object depend on how the client authenticates. For example, SimpleLogin's password provider puts the following into the auth token: provider, email, and id; any of which could be utilized in the security rules.
It's also possible to sign your own tokens from a server, and of course the sky is the limit here.
But the bottom line is that the token's internal values are provided by a trusted process and not by the client, and thus cannot be altered by a user.

Resources