I'm trying to build an app that works like a classic videogame, with some challenges that the user must complete in order to advance. Based on how the user solves the puzzles, he/she will gain XP points, badges etc. The user can quit the app and come back later, with an authentication system.
I'm planning to use Firebase Auth for authentication and Firestore for the database. It's the first time I use Firebase services in (somewhat) production environments, but I've been experimenting a lot with their services lately.
Firestore will be used to store a set of data for every user, but mainly his/her score. I'm somehow familiar with Security Rules in Firestore, and know how to make sure that only authenticated users can write to the db, perform data validation before giving write permissions etc.
However, there's one problem I cannot come up with: how can I be sure that the (authenticated) user will not use the browser console, or a custom API call to update his/her points and write them to the DB? Like in the first part of this video: https://www.youtube.com/watch?v=b7PUm7LmAOw&t
To sum up: my expected result would be that the (authenticated) user could update his/her score on my Firestore DB only by using the UI (i.e. solving challenges) and not by making a direct call to the DB. I thought of some other solutions (e.g. sending only user response - like answers to a quiz - to the DB and then updating the scores server-side with Cloud Functions), but it seems to me that I'm over-complicating a simple issue.
I've watched and read a good amount of guides on security in Firestore: they do a good job explaining how to secure an app from un-authenticated hackers, but I am yet to find a guide on how to defend the app against unwanted behaviour from authenticated users.
Thank you in advance for any guidance on this, deeply appreciate it. Stay safe :)
UPDATE: looks like the only way to manage data flow to the DB when you can't "trust" the authenticated user is using Cloud Functions. Thanks!
Listen to score, points, badges in real time using Firestore. You may set the security rules to these fields as READ ONLY for an authenticated user, setting write permission for a service user (that will be used in your cloud functions).
Send Quiz answers using a cloud function, that will be processed using your service authenticated user (with write permissions to the collections).
Thus, your cloud function may be responsible for checking answers and preventing user abuse from console and other methods.
Related
A hacker was able to create users in my client side based firebase site, I was restricting account creating by some sign up conditions on user's signup form data, I think he just injected signup code,
I immediately disabled authentication and removed the malicious accounts
If I used firebase cloud functions, will this hack still be able to create accounts, since firebase configuration was available to any client
are there any other actions ?
Update 4-9-2022
as temporary solution until using cloud functions, I made use of
making conditions using
https://firebase.google.com/docs/database/security/rules-conditions
if a user was created bypassing my logic I will make rules to disallow him from accessing certain paths
If you didn't do this already. You could fix this by adding some email verifier functionality. Or maybe try adding a captcha
Also check out: https://firebase.google.com/docs/auth/web/email-link-auth
Blocking the user by IP-address is pretty useless, so I can't really come up with another solution.
One question that you could ask yourself is, What is the reason they are doing this? If it is nothing too serious you could just accept and delete all those accounts after the "hacker" stopped making accounts.
I searched other answers, but couldn't find a compatible solution.
We have an application built in vue which allows unregistered users to upload files within a limit.
For registered users we use JWT with a refresh and access token stored in a http only cookie.
I am looking for guides on best practice to handle anonymous users. Ideally I would like to
a) create a record in the database with a uuid with a role of 'anon'
b) store this uuid client side for the lifetime of this anonymous user i think local storage is sufficient so i can access it on the client.
c) provide a seamless upgrade to a registered user using the same uuid, so all the past interactions are recorded.
I do know that client side storage can be deleted, this is fine, in this case i will create a new uuid.
Do i have the right approach here using the technology stack i mentioned (Vue, JS, Node JS, MongoDB, JWT)
Suggestions of improving these methods are welcome.
Thanks.
Depends on use case, if your application requires the anonymous user to be upgraded to a normal user when he register then you may want to keep a record in DB, but you cannot handle the case when user deletes the local data; then you just need to start a fresh with this user is OK.
But you may want to consider some users might not be comfortable knowing that when they register you already have previous records due to privacy reasons when using app anonymously
I think from searching the web this is not technically possible but I want to ask again in case I'm missing something.
I have an app that uses Firebase. Reading and writing is locked down through security rules for authorised users only but there's certain information I want unauthorised users to be able to access (so I don't have to put a login wall in front of them, influencing churn).
What I want to know is, is there any way of locking down this read access that only my app can call the DB? I know I can lock down domains to prevent someone writing localhost scrapers but what's to stop someone cloning and re-skinning an app and pointing it to the same back end? Is it possible to achieve this using your certificates fingerprint?
There is no way to limit access to your database to just your app. That just doesn't match with the cloud-based nature of the Firebase APIs. Anyone that knows the URL of your database can in in principle access it, and security rule are the way to ensure all access is authorized.
Note that security rules are not an all-or-nothing approach: you can require sign-in for some parts of your database, while leaving other parts publicly readable. But you can't make the publicly readable parts only be readable by your own app.
Some previous questions on the same topic:
how to make sure only my own website (clientside code) can talk to Firebase backend? (pretty much my go-to answer for this)
How to allow only my app to access firebase without a login?
Restrict Firebase database access to one Android app
How to allow only my app to access firebase without a login?
Update: since May 2021 you can actually restrict access to just users of your App by implementing Firebase App Check.
I have found a solution that maybe helps you or anyone that have a similar question. I answered it in this question:
Restricting Cloud Firestore to a specific domain
I am working on a React web app with a Firebase back end.
I was thinking about the security implications of accessing and updating the database directly versus accessing and updating the database with the use of back end functions like Firebase Cloud Functions.
Is it possible for malicious users to change the source code of the web app in such a way that they can alter the database queries once the web app has been built for production?
Yes, that is quite possible and quite common. You should not rely on the source code of your app to ensure your business rules.
Instead you'll want to rely on a combination on authentication and authorization to secure your data.
Authentication means that you ask the user to sign in, so that you know who's performing a certain operation. In Firebase you'll want to use Firebase Authentication for that. If you don't want to prompt the user for credentials, you can use anonymous authentication.
Once you know the user, you can ensure that they can only perform operations they are authorized for. You could do this in a custom backend, like Cloud Functions. But I'd always first consider Firebase's built-in security rules. These are evaluated server-side, and provide a fairly simple way to authorize access. Since the syntax depends on which database you use, here are the docs for Firebase Realtime Database and for Cloud Firestore.
Also see:
How to prevent other access to my firebase
Swift: Firebase: How to ensure no one can access my db except my app
How Secure is Firebase Real-time (Online) database for Android?
Wondering if it's possible to have a webapp upload a file (userid.input.json) to Amazon S3, which triggers a lambda function that reads the file, does some processing, and saves the result as another (userid.output.json).
However userid.output.json should not be immediately accessible to the web application. The webapplication has to complete a Stripe payment and once the payment completes, the web application can access the (userid.output.json) file on amazon s3.
Before I ask how, I figured I'd first ask if this this scenario can be facilitated / architected on AWS?
Approach
Note that this is an update to the question based on more research. It looks like Amazon Cognito will be the perfect tool for signing in users and tying their user credentials to an IAM role that can read and write to S3 buckets.
So once the user is signed in through Amazon Cognito and has the proper credentials then their files can be uploaded to an S3 bucket and processed by a lambda. The result is then written to the same bucket.
Now earlier I suggested writing to a sealed bucket and having a Stripe webhook trigger moving the result from the sealed bucket to an accessible bucket. But it seems this is necessary, per the indication in the answer provided by #Snickers3192.
Once the stripe payment completes the webapp can set a boolean that is used to control access to the output and that completes the cycle?
Part of the rational for having a hidden bucket was that someone might pull the credentials out of the browser and execute them in a different script. I assume this is impossible (Famous last words :) ), but just in case I wrote a follow up question here.
In other words the credentials that are pulled into the client post signin with Amazon Cognito cannot be used to executed scripts outside of the application context?
Approach Part 2
Per my follow up questions it does not appear that relying on state within the webapp for making security decisions is good enough, as someone can probably figure out a way to get the token authentication token and manipulate the applications API directly using a client other than the core app.
So now I'm thinking about it like this:
1) Write the result to the sealed bucket (Processing Lambda)
2) Have the Stripe webhook update the users a transaction record in the users profile indicating payment paid = true (Stripe Lambda)
3) Create another lambda that has access rights to the sealed bucket but will return results only if paid=true. (Access Result Lambda)
So since Stripe is tied to an IAM user that is allowed to update the Application user profile and set paid=true and the sealed bucket can only be accessed by lambda that first checks if paid=true before returning the result, I believe that should guarantee security.
If anyone has a simpler approach please let me know.
This really is more a question of where you want to put the security, which in AWS there are many options, in your application logic which could mean:
Lambda/Webapp
S3 policies
IAM roles/groups
These decisions are usually dictated by where your identity store is kept, and also if you want to keep the notion of AWS users VS. users of your app. My preference is to keep these two pools separate, in that security logic like this is kept in the webapp/lambda and AWS security only deals with what rights developers have to the environment as well as what rights applications themselves have.
This means the webapp can always access the input and output buckets, but it keeps a record in a database somewhere (or makes use of your payment system API) who has paid and who hasn't paid and uses that information to deny or grant access to users. IMO this is a more modular design, and it enables you to lock down your AWS account better and is more clear to developers where security is located. In addition if you do go with IAM/S3 it will be more difficult to run and debug locally.
EDIT: After all your comments and additional security concerns you may also want to consider emailing a short lived URL link to the processed file, so that a user needs both email access as well as knowing their credentials to the application. This will mean even if your access token is stolen at the browser level, without the email access a hacker still can't get the processed file. If you want to be EXTREME SECURITY CORE, have the link that not only is authentication required, but also MFA so that they need to enter in a code which is constantly refreshing as you should have setup for your AWS account when you login.
I'm by no means a security expert but just follow best practices and do your due diligence and you will meet security expectations.