I am setting up my app so that any client device can only impact collections/sub-collections that they own. However, to interact with other users, a user will need to make the app create a row in another user's collection. What is the safest way to do this?
My idea for this would be to have the app call a cloud function to create the record in the other user's collection. The cloud function would read the request and make sure of the following:
The incoming request has an existing UID
The incoming request's user's email is verified
The incoming request's UID has a record in the Firestore 'users' collection
If I do this, is this just as secure as using Firestore security rules?
The question you're asking is unfortunately not as easy to answer as you expect. Firestore security rules don't ensure general "security" of your app any more than backend code. Rules let you specify rules for reads and writes according to the conditions you provide, if you want to use them. If rules are not sufficient for the requirements at hand, then maybe backend code will work better. In either case, you can allow or deny access based on conditions you provide.
In terms of functionality, both options allow you to allow or restrict access in different ways. Neither one is more or less "secure" than the other. The main issue you should consider is which one lets you most easily specify those rules. Security rules are fundamentally more limited in what you can check, while backend code is fundamentally more flexible. The option you choose is dependent on what you're trying to allow or reject.
The constraints you specified in the question could be enforced by either security rules or backend code, so I don't see that one is necessarily more or less secure than the other.
Currently I have a user collection with user documents inside and each user has a currentPoints integer field that can get updated from inside the application via a button click
transaction
.update(couponCollectionReference, {
'currentPoints':
FieldValue.increment(10),
});
If someone decided to reverse engineer my app, can they just change the increment to FieldValue.increment(1000) instead, compile the app and just use it like that ?
I am wondering if I should just use cloud functions for the major of these operations
Transactions are designed to protect against race conditions between multiple users, but are not a security mechanism against abuse.
You can catch many forms of abuse in the server-side security rules that you can write for your database. I've written secure voting systems with that, so likely your case can be secured through rules too.
If you search for the [google-cloud-firestore][firebase-security] tag combination, you'll find many questions about the topic.
That said, many developers new to Firebase's security rules are more familiar with securing access through server-side code, which is fine too.
I am building a timetable system using Firestore as a database (and Angular v9.). I need a way to store only VALID data in the database.
I realize that with Firestore rules, I can set rules for providing access to the user to read or write. But how do I check if the value being stored is correct or VALID? For example, in my case, check if the slot is already assigned. So that when a new slot is being added, it doesn't overlap...
Do I need a server or a proxy or cloud functions? Or is it possible in Firestore directly? Or perform the validation in the frontend only? I believe that checking the data in the frontend would be the worst way to do so...
If the validations you're trying to perform can't be done in security rules, then you will need to provide your own backend the exposes APIs for your app to use. Instead of adding the data directly to the database, it would send the document data for the backend to validate and add. You can certainly use Cloud Functions for this (and a full discussion is beyond the scope of Stack Overflow answer), but you have essentially unlimited options here.
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.
Let's say I'm developing app like Instagram: for iOS, Android and Web. I decided to use Google Firebase as it really seems to simplify the work.
The features user needs in the app are:
Authorization/Registration
Uploading photos
Searching for other people, following them and see their photos
I come from traditional "own-backend" development where I do need to setup a server, create database and finally write the API to let the frontend retrieve the data from the server. That's the reason why it's unclear to me how it all works in Firebase.
So the question is how can I create such app:
Should I create my own API with cloud functions? Or it's ok to work with the database directly from the client-side?
If I work with the database directly why do I need cloud functions? Should I use them?
Sorry for such silly questions, but it is really hard to get from scratch.
The main difference between Firebase and the traditional setup you describe is that with Firebase, as far as the app developer is concerned, the client has direct access to the database, without the need for an intermediate custom API layer. Firebase provides SDKs in various languages that you would typically use to fetch the data you need / commit data updates.
You also have admin SDKs that you can use server-side, but these are meant for you to run some custom business logic - such as analytics, caching in an external service, for exemple - not for you to implement a data fetching API layer.
This has 2 important consequences:
You must define security rules to control who is allowed to read/write at what paths in your database. These security rules are defined at the project level, and rely on the authenticated user (using Firebase Authentication). Typically, if you store the user profile at the path users/$userId, you would define a rule saying that this node can be written to only if the authenticated user has an id of $userId.
You must structure your data in a way that makes it easily readable - without the need for complex database operations such as JOINs that are not supported by Firebase (you do have some limited querying options tough).
These 2 points allow you to skip the 2 main roles of traditional APIs: validating access and fetching/formatting the data.
Cloud functions allow you to react to data changes. Let's say everytime a new user is created, you want to send him a Welcome email: you could define a cloud function sending this email everytime a new node is appended to the users path. They allow you to run the code you would typically run server-side when writes happen, so they can have a very broad range of use-cases: side-effects (such as sending an email), caching data in an external service, caching data within Firebase for easier reads, analytics, etc..
You don't really need a server, you can access the database directly from the client, as long as your users are authenticated and you have defined reasonable security rules on Firebase.
In your use case you could, for example, use cloud functions to create a thumbnail when someone uploads a photo (Firebase Cloud Functions has ImageMagick included for that), or to denormalize your data so your application is faster, or to generate logs. So, basically you can use them whenever you need to do some server side processing when something changes on your database or storage. But I find cloud functions hard to develop and debug, and there are alternatives such as creating a Node application that subscribes to real time changes in your data and processes it. The downside is that you need to host it outside Firebase.
My answer is definitely NOT complete or professional, but here are the reasons why I choose Cloud Functions
Performance
You mentioned that you're writing an instagram-like mobile device app, then I assume that people can comment on others' pictures, as well as view those comments. How would you like to download comments from database and display them on users' devices? I mean, there could be hundreds, maybe thousands of comments on 1 post, you'll need to paginate your results. Why not let the server do all the hard work, free up users' devices and wait for the results? This doesn't seem like a lot better, but let's face it, if your app is incredibly successful, you'll have millions of users, millions of comments that you need to deal with, server will do those hard jobs way better than a mobile phone.
Security
If your project is small, then it's true that you won't worry about performance, but what about security? If you do everything on client side, you're basically allowing every device to connect to your database, meaning that every device can read from/write into your database. Once a malicious user have found out your database url, all he has to do is to
firebase.database().ref(...).remove();
With 1 line of code, you'll lose all your data. Okay, if you say, then I'll just come up with some good security rules like the one below:
This means that for each post, only the owner of that post can make any changes to it or read from it, other people are forbidden to do anything. It's good, but not realistic. People are supposed to be able to comment on the post, that's modifying the post, this rule will not apply to the situation. But again, if you let everybody read/write, it's not safe again. Then, why not just make .read and .write false, like this:
It's 100% safe, because nobody can do anything about anything in your database. Then, you write an API to do all the operations to your database. API limits the operations that can be done to your database. And you have experience in writing APIs, I'm sure you can do something to make your API strong in terms of security, for example, if a user wants to delete a post that he created, in your deletePost API, you're supposed to authenticate the user first. This way, 'nobody' can cause any damage to your database.