It appears that when someone authenticates via oAuth, Firebase creates a uid that looks something like google:111413554342829501512, for example.
In Firebase rules, you can do (read and/or write):
".read": "root.child('users').child(auth.uid).child('isAdmin').val() == true"
Is it assumed that I can't read the message by sniffing the network because of the use of HTTPS? Is this how it works - the UID is a shared key used by Firebase rules?
I see that UID in firebase:session::ack in Local Storage in my browser once authenticated.
Knowing someones user id is not a security risk.
For example, I know that your Stack Overflow user id is 4797603. That fact alone allows me to potentially find you on Stack Overflow.
But it does not in any way allow me to pretend that I am Ron Royston. To do the latter I'd need to know the username and password (and any other factor) that you use to sign-in.
The same applies to Firebase. If you know that my uid in some Firebase-backed application is google:105913491982570113897, you cannot suddenly pretend to be me. The Firebase servers verify that the auth.uid value is based on the actual credentials of that user. The only way to do is by signing in as me, which in this case requires you to know my Google credentials.
I advise to use custom ID along side with UID. When your app grows, you do not want to share the UID or pass it around. Also when setting firebase-rules, you'll be referring to UID, which should be kept private.
generate a random string for the ID.
And for sensitive user data, set a rule in firestore, to only allow reading of the document if request.auth.uid == user.uid. This will prevent unwanted access. Read up a bit more on firestore rules, might be relevant for your use case.
Related
It appears that when someone authenticates via oAuth, Firebase creates a uid that looks something like google:111413554342829501512, for example.
In Firebase rules, you can do (read and/or write):
".read": "root.child('users').child(auth.uid).child('isAdmin').val() == true"
Is it assumed that I can't read the message by sniffing the network because of the use of HTTPS? Is this how it works - the UID is a shared key used by Firebase rules?
I see that UID in firebase:session::ack in Local Storage in my browser once authenticated.
Knowing someones user id is not a security risk.
For example, I know that your Stack Overflow user id is 4797603. That fact alone allows me to potentially find you on Stack Overflow.
But it does not in any way allow me to pretend that I am Ron Royston. To do the latter I'd need to know the username and password (and any other factor) that you use to sign-in.
The same applies to Firebase. If you know that my uid in some Firebase-backed application is google:105913491982570113897, you cannot suddenly pretend to be me. The Firebase servers verify that the auth.uid value is based on the actual credentials of that user. The only way to do is by signing in as me, which in this case requires you to know my Google credentials.
I advise to use custom ID along side with UID. When your app grows, you do not want to share the UID or pass it around. Also when setting firebase-rules, you'll be referring to UID, which should be kept private.
generate a random string for the ID.
And for sensitive user data, set a rule in firestore, to only allow reading of the document if request.auth.uid == user.uid. This will prevent unwanted access. Read up a bit more on firestore rules, might be relevant for your use case.
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
I was recently having an argument with another programmer mate of mine regarding storing Firebase Auth UID (just the uid nothing else) in a cookie with sameSite: 'strict' enabled.
What's the argument about
Currently, I am working in a Nuxt JS project where I am saving the user's uid on onAuthStateChange() event in a cookie with sameSite: 'strict' enabled so that I can grab it in my serverMiddleware code and do stuff with it.
I have checked this firebase doc about managing cookie and it shows how to store the JWT idToken in a cookie and then in the server decode it.
In fact, that is who I initially coded my work. But due to some requirements, it was super helpful if I store the uid instead. So, I did that. Then I started reading about how can I hack my own data to see if anyone can harm my data from the uid in the cookie.
Then I stumbled upon to this firebase doc: Use the Cloud Firestore REST API which shows how to get the firestore data using REST API and I figured out that you need to provide Google OAuth 2.0 token in the header of the API call in order for it to work, otherwise even if you put the correct URL with all the collection name and everything (which is hard for an outsider to know, but lets assume he knows), you will get nothing but this:
{
"error": {
"code": 403,
"message": "Missing or insufficient permissions.",
"status": "PERMISSION_DENIED"
}
}
I have also tried to run code in browser console in order to hack the data out of my project. But That didn't work as well.
Now in order to get the Google OAuth 2.0 token, the person must need login access to my account which is not that easy as I have a unique long password along with 2 Step Authentication with phone OTP & push notification. Besides if anyone has login access to my Google account, he can easily go to console.firebase.com and see the data, so at that point, nothing will matter.
But I did say that if anyone is using firebase Realtime database then I will not recommend storing the uid in a cookie as the realtime database provides easy REST API without any authentication layer to fetch data. At that time I would recommend using JWT idToken instead.
So, what's the final question?
The final question is this:
If someone is using firebase auth & firebase cloud firestore (not realtime database) using firebase SDK in his project, is it secure to store just the uid in cookie instead of storing JWT idToken if it will reduce the code complexity and code execution time over using idToken?
I would love to know your thoughts on these as there are many super experienced devs beside two programmers arguing.
My friend keeps telling me that storing uid in the cookie is not sure, but when I asked him why exactly, he had no concrete answer. As what is secure and what is not a universal thing and changes as you change your tools. But in this exact context what do you guys think? I know that normally in most cases it is not a secure thing, but I am asking about this specific context only.
It is in fact fairly common to expose the UID of a user to other user to identify that user. See Firebase - Is auth.uid a shared secret?
There is nothing insecure about storing the UID in a cookie, nor in reading that cookie in your middleware. But if your middleware then assumes that the UID is the authenticated user, you have a security risk.
What is keeping any other user from putting your or my UID into that cookie, and thus getting access to your or my data?
Also note that UIDs don't change over time, so if ever one (even inadvertently) leaks, you could impersonate that user forever.
ID tokens on the other hand have a limited lifespan (currently about an hour), which limits the risk if they accidentally get exposed.
We are using Firebase custom authentication and want to define read/write access rules based on the "auth" payload data. However, for security reasons, we do not want to store the value of auth.uid anywhere in Firebase data. That is, since the user id for example is not part of the data, I cannot use the rule:
auth.uid == newData.child("userId").val()
Is there a way to just pass data to Firebase only for checking in the security rule, but not actually persist the data in Firebase db?
There are three possible sources of data for security rules: Hard coded strings, the database data, or the authentication token (i.e. auth).
You can generate your own authentication tokens, allowing you to specify any information you would like, without storing it in Firebase. Note that the contents of the security token cannot be forged by the user, but they can be read by the user; if your goal is to store some secret info users should not know, this isn't an option.
Note that you can secure any path in the database, so that it is not readable, store data in it, and security rules can still reference that data. Keep in mind that security rules cascade, so you want this data in its own path with no readable parents.
The security token mentioned in your comments sounds completely redundant of the user's auth token. If they have authenticated, you have already verified their uid, so it's unclear why a security token adds any additional value.
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.