I am managing a project with a lot of firebase real time database and a lot of data
I also need very precise security feature like masking certains
fields for certain user roles or masking data that contains field
related to the user...etc
I know that I can handle that using firebase security rules but at that scale, it's not readable nor maintenable at all.
So I want to handle all those security features serverside and proxy all request to firebase, so I wonder what is the best way to authenticate requests made by my backend to firebase knowing that ideally, I will not grant any user any rights on any databases.
Actually, I have tried to use a single "admin" user and make a simple security rule on all my firebase models like "read|write": "auth.uid === MY_ADMIN_UID" but I wonder if there is a better solution.
Could you point me to the right direction please?
I want to handle all those security features serverside and proxy all
request to firebase, so I wonder what is the best way to authenticate
requests made by my backend to firebase knowing that ideally, I will
not grant any user any rights on any databases.
Classically, in the Firebase model, if you want to interact with a Firebase service (e.g the Realtime Database) from a server you will use the Admin SDK. By default the Admin SDK bypass all Security Rules and has full access to your data.
In other words, requests from the Firebase Admin SDK are not gated by Security Rules. So it means that you can protect your RTDB with Security Rules that denies any access (i.e. ".read": false, ".write": false) in such a way a malicious user knowing the RTDB URL cannot query it.
This also means that you are in charge of controlling who is calling your proxy server before querying the RTDB from it.
HOWEVER, with the Realtime Database you can Authenticate with the Admin SDK with limited privileges, which IMO perfectly corresponds to your requirement, i.e. "best way to authenticate requests made by my backend".
As explained in the doc (see link above), you "use a unique identifier in your Security Rules to represent your service".
You then "set up appropriate Security Rules which grant your service access to the resources it needs" by using a specific identifier. For example:
{
"rules": {
"public_resource": {
".read": true,
".write": true
},
"private_resource": {
".read": "auth.uid === 'my-service-worker'", // <======
".write": false
},
}
}
And then, "on your server, when you initialize the Firebase app, you use the databaseAuthVariableOverride option to override the auth object used by your database rules. In this custom auth object, set the uid field to the identifier you used to represent your service in your Security Rules". See the examples for Java, Node.js, Python and Go in the doc.
Note that this still means that you are in charge of controlling who is calling your proxy server before querying the RTDB from it, but the Security Rules are less generic.
Related
I just set the rules of my Firestore project to only allow authenticated users to read/write to my database for added security. However, I also have an exterior Node.js webscraping script that runs in the background and needs to read/write to my Firestore database. There is no authentication involved, meaning it no longer has access to my database. Is there a way to allow the Node.js script to bypass the Firestore rules?
My rules:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
You can use the Firestore Admin SDK for Node.js to do your reads and writes. Security rules do not affect calls made by the Admin SDK's.
It is important that this webscraping script is not user-controllable. Make sure to deploy it in an environment where only you, and not your app's users, have access.
In my frontend react project I exported a firebase instance :
firebaseApp.js
import * as firebase from "firebase/app";
import "firebase/auth";
import "firebase/storage";
export default firebase.initializeApp({
... <props>
});
Whenever I need to use firebase in my project, I do this :
import firebaseApp from "../firebase/firebaseApp";
[...]
await firebaseApp.auth().signInWithEmailAndPassword(email, password)
Knowing that Javascript is put client side as this is a frontend project, is there a way for people to open the browser console, access my instance of firebase and call for example :
firebaseApp.auth().createUserWithEmailAndPassword(email, password);
which will result in creating users without backend authorization, and allow bots to create users ?
Iow, can someone access a module instance from the browser and play with it ?
It is indeed possible to take the configuration data from your existing web app, and use that to call the API in another way than your code does. And that does indeed mean that users can create accounts outside of your app.
Firebase makes a clear split between authentication (the users prove who they are) and authorization (the is is granted access to data). Firebase Authentication takes care of the former, while you use security rules (see below) or server-side code to take care of the latter.
For this reason you should never trust that the code that accesses your project is the same code that you wrote. So instead of assuming it's your application, think of what you want a user (no matter what code they use) to be able to do.
For example, if you're using one of the Firebase's databases (the Realtime Database or Cloud Firestore), you'd use their built-in server-side security rules to ensure any user can only access the data they're authorized for. In that case it doesn't matter if the user used your code, or wrote their own code: they'll have to follow those server-side security rules.
This is a common concern, so I recommend also reading some of these questions and answers:
Is it safe to expose Firebase apiKey to the public?
Restrict access to Firebase storage so only my app can access it
Locking down Firebase DB access to specific apps
I'm using Firestore as an MVP DB for an API we've got hosted on Heroku. The API doesn't use any authentication outside the OAuth provided by platforms like Slack and Google, and we're also not using any of Firebase's authentication
I'd like to change our security rules away from the insecure
allow read, write: if true; but I'm unsure how to write these rules in my context given most of the docs show security rules using Firebase auth or collection visibility
So, a couple questions:
Is it secure "enough" that I'm using the Firebase admin SDK on the Heroku server to access Firestore, but that my security rules basically allow access to anyone?
If not, How can I write rules that allow access only to a specific Heroku API endpoint?
Alternatively, are there better practices I should use to secure the data?
Thanks so much
The Admin SDK to access the database with special administrative privileges, and bypasses the security rules. So if you only access the database through the Admin SDK, you can lock the database for access by regular users with:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}
For an MVP, I think allow read: if True is not really a problem, depending the data you make available. However, on write, you can easily implement a rule with the incoming data, like that for example :
allow write: if request.resource.data.securityKey === 'custom key shared between firebase and heroku'
A better option would be to use the auth module firebase.auth().signInWithEmailAndPassword(email, password), store an email and password in the env variable of your heroku app and auth from there.
Firebase provides database back-end so that developers can focus on the client side code.
So if someone takes my firebase uri (for example, https://firebaseinstance.firebaseio.com) then develop on it locally.
Then, would they be able to create another app off my Firebase instance, signup and authenticate themselves to read all data of my Firebase app?
#Frank van Puffelen,
You mentioned the phishing attack. There actually is a way to secure for that.
If you login to your googleAPIs API Manager console, you have an option to lock down which HTTP referrer your app will accept request from.
visit https://console.developers.google.com/apis
Go to your firebase project
Go to credentials
Under API keys, select the Browser key associated with your firebase project (should have the same key as the API key you use to initialize your firebase app.)
Under "Accept requests from these HTTP referrers (web sites), simply add the URL of your app.
This should only allow the whitelisted domain to use your app.
This is also described here in the firebase launch-checklist here: https://firebase.google.com/support/guides/launch-checklist
Perhaps the firebase documentation could make this more visible or automatically lock down the domain by default and require users to allow access?
The fact that someone knows your URL is not a security risk.
For example: I have no problem telling you that my bank hosts its web site at bankofamerica.com and it speaks the HTTP protocol there. Unless you also know the credentials I use to access that site, knowing the URL doesn't do you any good.
To secure your data, your database should be protected with:
validation rules that ensure all data adheres to a structure that you want
authorization rules to ensure that each bit of data can only be read and modified by the authorized users
This is all covered in the Firebase documentation on Security & Rules, which I highly recommend.
With these security rules in place, the only way somebody else's app can access the data in your database is if they copy the functionality of your application, have the users sign in to their app instead of yours and sign in/read from/write to your database; essentially a phishing attack. In that case there is no security problem in the database, although it's probably time to get some authorities involved.
Update May 2021: Thanks to the new feature called Firebase App Check, it is now actually possible to limit access to your Realtime Database to only those coming from iOS, Android and Web apps that are registered in your Firebase project.
You'll typically want to combine this with the user authentication based security described above, so that you have another shield against abusive users that do use your app.
By combining App Check with security rules you have both broad protection against abuse, and fine gained control over what data each user can access.
Regarding the Auth white-listing for mobile apps, where the domain name is not applicable, Firebase has
SHA1 fingerprint for Android apps and
App Store ID and Bundle ID and Team ID (if necessary) for your iOS apps
which you will have to configure in the Firebase console.
With this protection, since validation is not just if someone has a valid API key, Auth domain, etc, but also, is it coming from our authorized apps and domain name/HTTP referrer in case of Web.
That said, we don't have to worry if these API keys and other connection params are exposed to others.
For more info, https://firebase.google.com/support/guides/launch-checklist
I'd like to use Microsoft Live/Connect/Passport (did I miss anyone?) identities with Silverlight/RIA.
This has a number of advantages:
Avoids foisting yet another username/password pair on people
User account management is wholly delegated to Passport and forms no part of my application or its UI
Responsibility for security and availability is removed to the company that everyone loves to hate
Now, RIA uses the membership stack from ASP.NET, which by default backs onto aspnetdb in SQL Server.
I'm looking into implementing MembershipProvider. So far I've set up appropriate references and overridden MembershipProvider, letting the IDE stub all the methods that need implementation.
I've set EnablePasswordReset and EnablePasswordRetrieval to return false, because my app does not provide these services. ValidateUser(username, password) is implemented and working, using WebClient to delegate the check to Microsoft's servers. Yet vast hordes of methods remain, all threatening NotImplementedException, and I have no idea which ones RIA might call. This leads me to...
The question
Does anyone know how much of MembershipProvider I actually need to implement, given that user account management is wholly delegated to Passport?
It crosses my mind that even though authentication and account management are delegated, it may be prudent to cache credentials. Once an identity is established, it would be preferable if it could be used in the absence of an internet connection. For example, you can still use your Passport credentials to log onto a Surface RT when it doesn't have an internet connection.
Perhaps I should inherit from SqlMembershipProvider, so that ValidateUser checks whether a username is locally known, and if not tries the credentials with Passport and - if they pass - implicitly creates the local user, and if it does exist but the credentials fail, checks with passport in case the local password is stale, updating it if Passport accepts the password.
If you like the idea, your input is solicited.
With the Custom MembershipProvider, you only need to implement,
GetUser
ValidateUser
Another thought, with LiveID, it supports Security Token Service, so you can use Windows Identity Framework see here
Getting Live ID to work via WIF