I appreciate that variants of this have been posted before, however I am not seeing one that directly hits this concern. The Firebase recommendation is that for Web interfaces the JS includes enough information for the client side JS to identify the application in question. This config can be used for all the activities that are needed. In my case :
createUserWithEmailAndPassword / signInWithEmailAndPassword / sendEmailVerification
Basically this means that anybody can simply start creating users for my application. They can also sign-in, which means any data rules I have that, an example like below, are now open to the world for updates.
service cloud.firestore {
match /databases/{database}/documents {
function isSignedIn() {
return request.auth != null;
}
match /clubs/{club}
{
allow write: if isSignedIn();
allow read: if true;
}
}
Here is what I have done. I have added a Role to the User list, and the User list is not writeable by anybody except my back-end processes which bypass the rules.
Therefore although malicious people could create accounts and sign-in, they could never give themselves the most vital Roles. It still leaves me with 2 issues, firstly it just does not feel quite right :-), secondly how do I know which accounts are valid people trying to sign-up for my application and which are bogus. Those that are valid need their Role updating in the back-end. Right now when I have like 5 users of my app it is ok (haha), but how do people manage this in a more voluminous application?
I appreciate you taking the time to read this and I appreciate any thoughts and / or suggestion you might have.
if you need more granular control around your roles, you can check custom claims
Also, there are a few posts around which tell you a few patterns, take a look:
Controlling Data Access Using Firebase Auth Custom Claims
Patterns for security with Firebase: supercharged custom claims with Firestore and Cloud Functions
there's enough information there to get you started.
Related
After finishing development for my application, I realised that I had left the insecure rules on as it was my first major project with Firestore and I had to fix some issues and I changed the rules to allow me to use it. When I went to turn it off, the whole application stopped working as it only accesses it through these rules. I have read a lot of responses here and am aware this question has been asked many times before but I am truly stuck and have no idea how to proceed.
Currently there is no signup required as it is on a shopify app - store owners must be signed in to use it and so the database has an area such as /users/ where each entry is the store name and holds it's associated data (so people do not need accounts to use it). There is also an exterior portal on Retool that edits all of these records on the database - I believe this complicates things as I feel like two sets of rules are required.
My current rules:
// Allow read/write access to all users under any conditions
// Warning: **NEVER** use this rule set in production; it allows
// anyone to overwrite your entire database.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
I am now aware that store owners could wipe or steal the data of other shop owners and so far have set up daily backups, but haven't been able to fix this issue. I would like to know if it is possible for me to set the database up in such a way that allows store owners to still read/write to their sections but also the people using the Retool portal that interacts with db to have access.
I have no idea how to proceed and any help would be sincerely appreciated. I saw something saying about limiting users to using an extra layer of server's REST api but have no idea how I would go about implementing this and if I would have to change rules.
So if I have an E-commerce App that doesn't require Login/Auth, and my users buy in the store, then after verifying the transaction the backend writes the order in the database.
The thing is that my Realtime Database just relies on Stripe transaction key (i.e, someone has paid for an item) to be able to write on the DB, because my rules are set so anyone can write, otherwise I would need every user to log in, but that's not what I want.
Firebase recently notified me that my rules are weak.
How can a make sure my users are able to write to my database in a secure way for my app, without log in/Auth?
There are many different security models you can use with Firebase, and it's important to understand the level of security each provides.
One thing to look into is anonymous auth which lets you "authenticate" a user without actually requiring them to provide any credentials. This provides a way to guarantee that the same device is being used between multiple reads/writes.
In your specific case, it sounds like you might be looking to rely on unguessable tokens. This can be a valid security model for some use cases so long as the key is sufficiently complex as to be unguessable.
At its most basic, the way you'd structure security rules for unguessable URLs is something like:
{
"rules": {
"transactions": {
"$key": {
".read": true,
".write": true
}
}
}
}
This allows users to read/write specific nodes at e.g. transactions/abc123xyzunguessable but importantly does not allow reading/writing to the parent transactions node. Security comes from the fact that only the person who originally got the unguessable token will be able to provide it again in the future.
A better implementation would gate writing on the $key matching the expected unguessable format, adding validation and other read/write rules to ensure that the data is formatted appropriately, and probably also prevent modification of key fields.
These are just some pointers but should help you on your way. The important thing is to make sure that you never leave important information in a place where it can be read through easily guessable URLs.
There is no "secure" way to allow writes to Realtime Database without Firebase Authentication. Without Firebase Auth, either there is full public access, or there is no public access at all.
If you can't use Firebase Auth, what you will need to do instead is make your security rules disallow all direct access to the database from client applications, then create backend APIs to manage access to the database. Your backend APIs will need to somehow validate that the person making the request should have the ability to make the required changes. Then, it will have to use the Firebase Admin SDK to commit those changes to the database.
I'm working on a PoC (Proof of Concept) application that users can download wallpapers to their device. All of the data is served using Cloud Firestore & Storage.
There is NO LOGIN for this application. Anybody can download the application, and immediately download the wallpapers she or he desires.
Bearing that in mind... I would like to have a counter that tracks how many times each specific wallpaper was downloaded.
While I have it "working" - I am questioning the rules I have set up in Firebase..
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read;
allow write: if request.auth != null;
allow update: if request.resource.data.counter is number;
}
}
}
My thought process with the rules above:
Anybody can read.
Only authenticated users can write. (I am managing all of the data with a headless CMS; Flamelink; so the 1 and only authenticated user is myself.)
Update the counter if the data is a number..
It's that last rule that I am questioning.
Is this a safe method of security to deploy to production?
Again - no login for this application, users can download all of the wallpapers with no authentication, and there will be a counter next to each wallpaper for users to see how many times each wallpaper has been downloaded.
The rules are not "secure" by any normal definition of that word. Here's what they allow. Anyone with an internet connection who knows the name of the project (which is easy to get) can:
Query for any document in the database
Update any existing document with any numeric value for counter in any document (it doesn't even have to increment, or be a positive integer)
On top of that, anyone who is able to get their Firebase Auth ID token (again, not terribly difficult for determined attacker), can fully create and write any document in the database. If you say there is no Auth at all in your app, then this is not really an issue, but if your project is configured to allow any form of authentication, it would be possible for an attacker to start writing anything.
You will get email from Firebase saying that your rules are not secure, mostly because you're allowing everyone to read everything.
What you should do is define more specifically what your security requirements are, then translate those into rules that actually meet those requirements. If you want to allow unauthenticated write access to your database of any kind, you are in a bit of trouble, as there is no way to make sure that the access actually matches the download behavior you're trying to measure. You'll be better off counting the downloads in whatever process manages the download, which is probably going to require a more sophisticated backend than what you have now.
But if allowing public read/write access is indeed what you want to allow, you'll be better off by making your rules more specific. For example, you can limit which collection the anonymous user can write to, and making sure they can only ever increment the counter, if these are the things you want.
We have an iOS app that uses Firestore. The app only reads data (no writes), we have no user accounts and nothing on the database must be protected. For that reason we ran with these naive security rules
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read;
}
}
}
However, Firebase has warned us (sure, for good reasons) that this puts us at risk for two reasons:
Any user can read anything from the database, therefor nothing is secure.
I don't see this as a problem because we have nothing that must be kept secret. At least for now, sure, that might change.
Unlimited reads are permitted
This is were the problem lies. I suppose a malicious user could read our database millions of times and thereby shut us down or simply force us to pay a large bill (we use the Blaze plan, pay as you go).
How can we protect us from this? I've seen similar questions here but they don't provide any helpful suggestions, How to limit rate of data reads from Firebase?
My idea is that we could use anonymous user accounts in the app and then in our security rules only allow read if user is "logged in" (thereby anyone using the app). I'm far from an expert on Firebase and security issues, but wouldn't this at least make it harder or impossible, for someone to read our database millions of times because it must be done through the app?
Any other suggestions how we may approach this?
There's not really a way to throttle the read rate for a particular client app once you allow read access to a document. With fully public read rules, everyone on the internet could read documents repeatedly to run up a bill. The chances of that happening are really slim though, and you should report what appears to be abusive behavior to Firebase support.
You can get rid of the warning message by calling out the individual top-level collection you would like the clients to be able to read. Since Firebase doesn't know which collections you might want to allow or disallow access to, you should be explicit. For example, something like this for each collection:
match /collection1/{document=**} {
allow read;
}
match /collection2/{document=**} {
allow read;
}
If you do this, be sure to remove the rule you have now that allows access to all documents.
If it's just read only operation then you can consider using remote config, as remote config is completely free.
But if it's necessary to use firestore database for your scenario, then consider Firebase Anonymous sign-in and setting the following security rule
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /collection_name/{documentId} {
allow read: if request.auth.uid != null;
allow write: if false;
}
}
}
I'm trying to create a rule to allow certain functions in my firestore db (I worked with firebase since 3 months ago, I'm really new in this). The main idea is to find the _key of the user profile that I have stored in an user document. Then, search all the permissions allowed in the user-profiles document with the id that I found before. If I found the permission, I'd get access to the function
service cloud.firestore {
match /databases/{database}/documents {
function getPermisos(idPermiso){
return get(/databases/{database}/documents/user-profiles/$(idPermiso)).data;
}
function getUserType(){
return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.profile._key ;
}
match /proyectos/{document=**}{
allow list,get: if getPermisos(getUserType()).acessList.proyectos==true;
}
}
}
Is this the right way to make it? Thanks in advance for any help
You don't query rules for accessibility. You can define a collection of accessLevels where each document represents your various access types such as "admins", "groupone", "grouptwo", etc. see documentation
Control Access with Custom Claims and Security Rules
The Firebase Admin SDK supports defining custom attributes on user accounts. This
provides the ability to implement various access control strategies,
including role-based access control, in Firebase apps. These custom
attributes can give users different levels of access (roles), which
are enforced in an application's security rules.
User roles can be defined for the following common cases:
Giving a user administrative privileges to access data and resources.
Defining different groups that a user belongs to.
Providing multi-level access:
Differentiating paid/unpaid subscribers.
Differentiating moderators from regular users.
Teacher/student application, etc.
Add an additional identifier on a user. For example, a Firebase user could map to a different UID in another system.