Should I query my Firebase database directly, or use Cloud Functions - firebase

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.

Related

Firestore client set() and field schema validation

I am creating a react native application using Firestore and I am not sure how to implement secure schema validation on document creation and update.
If I understand security rules, it is possible to:
Limit who can perform operations (update, read, write, etc.) on documents
Limit operations allowed based on field conditionals
Limit operations allowed based on custom functions (post w/ examples)
My concern is that because of the client side nature of the requests, a savvy user could utilize their authentication and some client side code to .set() any field or map/object to any value they want unless a security rule prevents it. It appears I could use very complicated custom functions to validate the data received. I could also validate every update and create through a Cloud Function API, but I am attempting to use the Firestore database itself whenever possible.
Am I right to be concerned about the potential for users to abuse their .set() field creation abilities on authorized documents (i.e. documents with minimal userId rules)?
Is there an accepted way to create security rules that prevent client abuse of documents that don't have custom functions that validate the schema?
You should always consider malicious users, and how they might affect your data, no matter whether you write the validation in security rules or in more traditional code in Cloud Functions.
Compare these two statements from your question:
"I could use very complicated custom functions to validate the data received"
"I could also validate every update and create through a Cloud Function API"
In both cases you're writing custom code to ensure the data the user enters is valid according to your business rules. Since these rules are specific to your business, there's no way to prevent you having to write them. The only difference is where you write these business rules. With Cloud Functions you're writing the validations in regular JavaScript code, in an environment you may already be familiar with. With security rules you're writing the validations in a domain-specific language, which you'll have to learn.
I personally far prefer writing my business rules into Firestore's server-side security rule language, and then use Cloud Functions for implementing business logic on top of that validated data.
If you are worried that user might just reverse engineer your app and mess up your code to harm your database, then yes this is possible. You should have proper rules set. Talking of updating data in database from app, try to update it through cloud functions as far as possible. This way you might need to give less access to your users to the database directly.
You can check my answer here. This will help you setting rules and some ways to code adapt your app code based on situation. The answer also has some lines on where can one use cloud functions to reduce direct contact with the database.
And if there is no know or you feel the information should be directly updated to the database, change your rules to this: ".write": "$uid === auth.uid" .
Here $uid is name of parent node and can be anything else. This way a user can access his/her data only and even if the user modifies your app, they can harm their data only. (You should have correct rules set).
You can check out this link for most of the rules combinations.
And do check the answer whose link is above. That might clarify how it will secure your database to some extent. If you can provide any particular situation regarding your app and want some information for how to set rules there, feel free to drop a comment :-)

How can any user write to my database securely in Firebase without Auth?

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.

Cloud Functions, Cloud Firestore, Cloud Storage: How to protect against bots?

I already use ReCAPTCHA for Android apps client-side (I've also implemented, of course, its server-side verification).
However, this ReCAPTCHA is implemented only in one activity. But, of course, hackers can modify the app. For example:
they can simply remove ReCAPTCHA from all activities,
or start another activity that would not have ReCAPTCHA implemented; it's the case btw: I didn't implement ReCAPTCHA in each activity because it's useless according to the first problem I've just mentioned.
So I would want to detect bot and spam requests in Cloud Functions, then in Cloud Firestore, then in Cloud Storage, for the following accesses: read, write, function call. It'd allow me to prevent unwanted contents from being saved in Firestore for example (spamming messages, etc.), and to avoid overreaching my monthly billing quota (because of spam requests to Firestore for example).
Is it possible? How?
There is no "spam detection" for these products. Your security rules will determine who can access what data. If you don't have security rules in place, and allow public access, then anyone will be able to get that data, and you will be charged for it when that happens. This is the nature of publicly accessible cloud services.
If you want more control over the data in these products, you could stop all direct public access with security rules, and force clients to go through a backend you control. The backend could try to apply some logic to determine if it's "spam", by whatever criteria you determine. There is no simple algorithm for this - you will need to define what "spam" means, and reject the request if it meets you criteria.
Google does have some amount of abuse detection for its cloud products, but it will likely take a lot of abuse to trigger an alert. If you suspect abusive behavior, be sure to collect information and send that to Firebase support for assistance.
Just thought I'd add that there is another way to restrict access to Cloud Functions.
Doug already described Way 1, where you write the access logic within the cloud function. In that case, the function still gets invoked, but which code path is taken is up to your logic.
Way 2 is that you can set a function to be "private" so that it can't be invoked except by registered users (you decide on permissions). In this case, unauthenticated requests are denied and the function is not invoked at all.
Way 2 works because every Firebase project is also a Google Cloud Platform project, and GCP offers this functionality. Here are the relevant references to (a) Configuring functions as public/private, and then (b) authenticating end-users to your functions.

Extending Firebase Users

I am currently building a multi-platform web application and I'm currently busy with the authentication of users. I'm using vue on the client-side and django and the backend with postgres as the db.
I thought I would try out using firebase's authentication as it would speed up the process as well as take care of various issues like security etc. I have now come across a bit of a problem:
I need to add extra fields the user (gender, address etc.)
I need to set user roles (admin, manager etc.)
I am aware about some kind of way to set user roles but not really sure. In terms of extending the user in my mind I have two ideas:
Either I use the UID from firebase as a identifier to an extended user class
in my backend db. But that kinda defeats the purpose of speed.
Use Firestore - not sure how I would go about doing this though.
plz help
I have written a blog and made a video on how you can use custom claims to assign roles to your users. Essentially, you apply custom claims on a secure backend like inside of Cloud Functions, and these can be used to control access to Firebase backend features like Cloud Firestore and the Realtime Database. You can also check out the Firebase guide for more information.
As for additional data about a user like gender and addresses, that should be stored in Cloud Firestore, the Realtime Database, or whatever database you choose to use. It is not information that you constantly need when accessing a User object.

Understanding the Firebase and purpose of google cloud functions

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.

Resources