I have been looking and playing with Firebase and I found it really interesting.
So far I have tried some simple authentication and security policy setting but now I have a problem which does not seem to be covered in the documentation and I couldn't find anything on Google or here.
The problem is that I cannot find a way to limit the number of concurrent logins per email/password.
I would like to have an option where paid customers can only login from 1 IP at a time. In other words I don't want people to be able to purchase an account and then share the same with friends and family and then all connect to the system at the same time using the same credentials.
Thank you in advance.
You will control access by writing to a path in Firebase whenever a user logs in. Then you can check that path to ensure only one user exists at a time:
write a value to a path each time a user logs in (e.g. logged_in_users/$user_id)
use onDisconnect() to delete that value when user disconnects
check that path for a value on an additional login attempt
show an error if the value exists or allow login if not
This takes care of the UX portion. To secure it against exploits, you will take advantage of Firebase's comprehensive security rules:
generate your own authentication tokens using the custom login strategy
include the IP address as part of the data inside the token
reject login attempts if the logged_in_users/$user_id is set to a different IP address
write security rules to prevent read/write from other IPs
Assuming you've generated tokens containing an IP address, your security rules could look something like the following:
".read": "root.child('logged_in_users/'+auth.uid).val() === auth.ip_address"
Related
I'm looking for some guidance and have had a hard time finding a straight answer via Google.
I am building a web app using Google Cloud Platform and Firebase and would like to grant users access to only their own subdomain. So for example, if user 1 is part of the organization Lakers, I would like the domain they use to be lakers.myapp.com. If user 2 is part of Bucks, their app would be hosted at bucks.myapp.com. When somebody who is not authorized visits one of these domains, they should not be able to view anything since they are not authorized under that subdomain (just like any normal web app). I have the login all set up and can redirect the user to their subdomain, but what is the process of checking that the user is authorized to view that subdomain?
If the answer has many parts, I would be happy to receive some links to resources on how to do this; I wanna be sure it's done right.
For the first part: (Can we restrict users ( Identity ) based on the GCP domains ?) , then answer is yes. The Resource Manager provides a domain restriction constraint that can be used in organization policies to limit resource sharing based on domain. This constraint allows you to restrict the set of identities that are allowed to be used in Identity and Access Management policies.
Organization policies can use this constraint to limit resource sharing to a specified set of one or more Google Workspace domains, and exceptions can be granted on a per-folder or per-project basis. For more information about adding exceptions, see Override the organization policy for a project.
For the second part:(How do I lock down Firebase Database to any user from a specific email domain ?). If you're using the new Firebase this is now possible, since the email is available in the security rules.
In the security rules you can access both the email address and whether it is verified, which makes some great use-cases possible. With these rules for example only an authenticated, verified gmail user can write their profile, please see the Stackoverflow Link for more details.
I'm making an app that has Firebase as its database. The app shouldn't need the user to create an account to use it, but I want the user to be able to read/write their data onto the database (so maybe they have to create an account?).
Do I have to make the users create an account in order to use Firebase?
My problem is that my security rules are read/write are allowed for everyone (which I know is wrong, but how do I change them and not need users to create an account?) Maybe that's the issue.
It is best to ask them to create an account
Although:
it can be a non-real email address and
there is anonymous auth also available
It sounds like you need the app to remember that user's particular data, so that when they return to the app, it is still their data (and not someone else's) that is being accessed.
To achieve that, we need each person's data to be stored in a different place in Firebase. Traditionally, this is by having them log in to some kind of system, most conveniently Firebase itself, and then the data stored in a branch of the database defined by their user Id.
Without logging in, you could simply ask the user for an identifier, such as "Bob" or "Carol", and then store their data under their identifier. The Firebase database would therefore have the following structure.
users/Bob/highScore: 3000
users/Bob/level: 7
users/Carol/highScore: 5050
users/Carol/level: 9
However this is not secure because there is nothing stopping Carol coming to the app and saying she is "Bob". Any such client-side activity you carry out to attempt to identify the user is not really authentication (in the opinion of Firebase) because all client-side activities can be faked relatively easily.
Firebase Authentication
The standard solution is to use Firebase to authenticate each user (see the Firebase authentication docs for this), and give your app a user Id (such as "8769dsg6f8g7698769876sdgs9") which is unique and known (by Firebase) to be correct.
Firebase security rules
You can then lock down the database using Firebase Security Rules so that only user 8769dsg6f8g7698769876sdgs9 can write to any of the users/8769dsg6f8g7698769876sdgs9/.... part of the database.
If you don't use Firebase to authenticate the user, Firebase will treat the user as unauthenticated and you will have no way to restrict each user to their own section of the database. Either you leave it wide open (to hackers etc!) or users will not be able to access their own personal data on it.
They can use a FAKE email address and password
If your concern is that they won't want to give out their real email address, you can ask them to make up any email address, e.g. mickeyMouse49857430679304#hotmail.com, and set a password. There is no obligation on your app to contact them on that email address or verify that the email address is correct.
Whenever they come back to the app, or access it on another device, they need to remember the fake email address and password.
Of course, if they lose their password, there is no way to reset it.
Anonymous Authentication, but at risk of losing access
The legendary Frank von Puffelen of Firebase, himself, has added a remark about Anonymous Authentication, in the comments below. From what I understand, this avoids them having to make up a fake email address.
I think the weakness of this is that if they lose their local web storage (e.g. if they manually wipe it, or move to another device), there is no way for them to re-access the same account, unless they have planned ahead by adding an email/pw to the anonymous account.
The only real way to have security per-user data storage is to use Firebase Auth to sign in the user, and write security rules to protect the database so that each user can only access their own data. There are no secure alternatives to this for Realtime Database.
I would like to track anonymous user actions as if the user would be authenticated. The goal is to let users perform actions(normally reserved to authenticated users), save it in Database with a special status (not visible until user will log into the application).
For example,
an anonymous user reply to a comment.
The system detect that the user is not logged in, save the comment with special status 'waiting for authentication'.
The system ask user to log in, in order to complete the registration of the comment.
User log into the application.
The system check for 'waiting for authentication' status and update/associate entries to the user authenticated.
Have you any suggestions / experiences to implement this type of functionality? Maybe Symfony has already in feature/bundle for that?
What you are trying to do is simillar to Lazy Registration, which is a proven concept. It is well implemented here at stackoverflow. It allows you to post messages after providing an email address. It works similar to this one:
http://www.90percentofeverything.com/2009/03/16/signup-forms-must-die-heres-how-we-killed-ours/
However, if you really want to go your way, without asking user for an email address, I would recommend storing data at browser local storage. It would save you a lot of work on backend side. Data would be transferred to the backend only when user registers. This way you will also prevent database pollution with users who never registered. http://blog.teamtreehouse.com/storing-data-on-the-client-with-localstorage
You could use ip address but it won't be very effective because one user can access your website from many ip addresses (wifi, 3g/4g connection ...).
You can rely on cookies but once he logs in from another device you can't do anything about it.
IMO, you should save actions and link them to a uniq token that you send to the anonymous user, once he's authenticated he can provide the generated token and then you save actions for that user. Becareful to not forget removing saved anonymous-actions once they are "identified".
If a user logs into my Firebase store with Google authentication, the client gets access to all sorts of useful user-specific information, like the user's name and email. I might want to put this information in the store, and the client can certainly send it along in a write request. But as far as I know, there's no way to validate (on the server side) that this information is correct. There is nothing stopping someone from using a second client to send fictitious metadata.
(For instance, take a look at the skeletal auth variable which is accessible from security rules. It doesn't contain the information I need for validation.)
How do people deal with this kind of situation?
Only limited information about the user is available in the auth variable in security rules.
To access more information, you'll have to store that information in the database when the user is created or signs in. Most developers add a /users node to their database for this reason.
You can then look the extra information up in your security rules with something like root.child('users').child(auth.uid)...
The process is covered in the Firebase documentation section on Storing User Data.
An example is say i have a child with lots of data in it and a user wants to attack my firebase to slow it down and increase my upload limit and sets to read this child over and over again not from my app but from their own creation.
How would i prevent this from happening when the child is a public child in that it does not require a user to be logged in to be read?
Is there a way to only allow a certain domain to access a firebase so that other users cannot just access my data from their domains?
Since all the data can be read via javascript and the javascript can be changed by the user can this also happen when someone changes the code on my site. Also is this a potential problem with all databases RDBMS or non RDBMs and not just with Firebase?
You might want to check out the "anonymous" login option provided by Firebase Simple Login: https://www.firebase.com/docs/security/simple-login-anonymous.html - this lets every visitor to your site authenticate with Firebase, and you can setup your security rules such that only anonymously authenticated visitors to your site can read data.
Most production apps will employ the security rules to restrict access to their data. Learn more about Firebase security rules here: https://www.firebase.com/docs/security/security-rules.html