Android | Firestore Rules | Check if username & phone already exists - android

I want to check if the user's username and phone number is unique. I have implemented it using
FirebaseFirestore.getInstance().collection("Users").whereEqualTo("phone",ph).get().addOnCompleteListener(...);
This is my firestore rule:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: true;
allow write: if request.auth.uid != null;
}
match /Users/{userID} {
allow update: if request.auth.uid == userID
&& (request.resource.data.username == resource.data.username
|| isUserNameAvailable(request.resource.data.username)
);
}
}
The code works fine with no issues. I am checking this before the signInWithCredential method and hence the request.auth.uid will always be null. To make the code work ill have to keep allow read: true;
But, now i am getting this warning
We've detected the following issue(s) with your security rules:
any user can read your entire database
Is there any workaround to prevent this?

This is a common mistake developers make when using usernames. You gave anyone permission to read your whole database. And even if you manage to put that to only read Users anyone could read all your users data.
I would recommend to remove the first allow read:true and write rules for each path as they should be. Also create a separated collection just for usernames and save all of them there like /usernames/${username} and /phones/${phone}. If the need to be saved together you can do that to.
That way you can very easy check without any query if a username or phone exists by just checking if that path exsists in your database.
You can very easy sync the users collection with those two and even write security rules that prevent creating users in the collection that have a username that already exists in the usernames collection.

Related

How to prevent a user in Firestore from creating and reading more than one document without using Firebase authentication?

I have a Firestore database that I only use to check if the user has passed the app's trial period. It has one collection called "users" and each document in it has its Document ID value set to the Settings.Secure.ANDROID_ID of the user it belongs to and it has one field inside it that's the timeStamp of when the user installed the app.
Currently the security rules are like this:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, create: if true;
}
}
}
I'm not using Firebase authentication because I don't want the user to have to login to Firebase in order to use the app.
Is there a way to set the security rules so that each user can only create and read one single document (his own)? I don't want a hacker to create millions of documents or to read other documents.
You definitely shouldn't rely on client side security. Firebase Authentication has a type called Anonymous. This will allow your user to start using the app in a way that you can control with security rules. If/ when they are ready to sign up, you can convert a user to a conventional sign-in provider.
https://firebase.google.com/docs/auth/android/anonymous-auth
The user ID assigned to the user of an Android app with Anonymous Authentication, persists until the app is uninstalled (I believe).
You can then add security rules to ensure that a user is only able to read/write to a single document in a collection or only read/write documents which they have created.
Write one document per user
match /users/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
Only read/write documents created by the user
match /mydocs/{mydocId} {
allow read, update, delete: if request.auth != null && request.auth.uid == resource.data.authorId;
allow create: if request.auth != null && request.auth.uid == request.resource.data.authorId;
}
Rules are not filters
With these rules, you will not be able to simply fetch all documents from the collection and only view those which match the user.
Get the user document
db.collection("users").document(userId).get()
Get documents authored by the user
db.collection("mydocs")
.whereEqualTo("authorId", userId)
.get()

How can I restrict users to retrieve only their data from Cloud Firestore?

I'm building an app with Kotlin. In the app, the user can sign up and log in. After the user log in, the user adds some text and pictures, and these data is successfully added to the firebase cloud store and displayed in the app as a list. However, this list can be accessed by anyone registered on the app.
What I want to do is how users can only see their own data. So I don't want users to see each other's data. I just want every user to see their own added data. I think that I need to change Cloud Firestore rules. How do I set permission to specific document?
I'm new to this field, Thank you !
My firebase Cloud Store rules;
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match/Notes/{noteId}{
allow read, write: if request.auth.uid != null ;
}
}
}
this is my firebase cloud store screen shot
it's done by settings up the rules. You can read more here: https://firebase.google.com/docs/database/security#section-overview

Firestore permissions; checking if a user is in an array

In Cloud Firestore, I have a collection of documents with an array field containing all of the users that should have read permission on that document. My simplified security rules are:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /collection_name/{document=**} {
allow read: if request.auth.uid in request.resource.data.listOfIds.toSet();
}
}
}
A sample simplified document is:
{
listOfIds: ["uid1", "uid2"]
}
Using the rules simulator to perform a get, reads work as expected. However, executing a similar query using the Android API returns a permission denied error. I think I'm constraining my query in the same ways the rules are (which is a requirement of Firestore; it doesn't filter out documents that the user can't read for you).
firestoreClient.collection("collection_name")
.whereArrayContains("listOfIds", firebaseUid)
.get()
.addOnCompleteListener(...);
It turns out, Firestore thought the query wasn't properly constrained to the defined read permissions. It was the .toSet() that threw it off. Removing that resulted in the behavior I expected.
Why did I have .toSet() to begin with? I had erroneously thought that converting the array into a set was a requirement to use the in operator. That operator works with lists as well as sets.

How to store data that is specific to users with firebase?

On the application I am developing, the user creates their account with e-mail and password but how can I make data specific to the user? For example, in my application a user can gain points by completing certain tasks. So when a user completes a task, I need to update their points and store it on the database so they can gain points overtime and use them to redeem awards. Here is what I think I am supposed to do, but I am unsure if I have to add anything to the rules or not.
Note: Every user's point amount is supposed to be unique to that specific user
If you want users to only be able to read/write their own data, you'll want to store that data under the user's UID. From the Firebase documentation on securely accessing user data:
Another common pattern is to make sure users can only read and write their own data:
service cloud.firestore {
match /databases/{database}/documents {
// Make sure the uid of the requesting user matches name of the user
// document. The wildcard expression {userId} makes the userId variable
// available in rules.
match /users/{userId} {
allow read, update, delete: if request.auth.uid == userId;
allow create: if request.auth.uid != null;
}
}
}
👍 yup looks good, just be careful about who has access to write to that document.

prevent a user from writing data to firestore if data exist

I am making an android app that when a user register an account on firebase, he saves his email, phone number and password. but when he wants to login, he uses his phone number and password. Because of that requirement I must also make the phone number unique There are a number of ways too do this but my options are limited because the database is already being used by a working system and me making changes to it will cause the other system not to work. The best way to solve my problem without affecting the other system is by modifying the rules to prevent a user from adding an phone number that already exist.
My database structure is like this
users {
userID {
name: "John"
phone: "2342222"
address: "23rd Avenue"
email: "email#mail.com"
}userID 2 {
name: "Mark"
phone: "2342222"
address: "5th Avenue"
email: "email#mail.com"
}
}
Now my rules look like this
service cloud.firestore {
match /databases/{database}/documents {
match /Users/{anything=**} {
allow write: if auth != null && !data.exists() && data == request.auth.uid;
}match /Users/{userId} {
allow read: if request.auth.uid == userId;
// I need a rule maybe here that will allow me write phone number to the database
// If the number doesn't exist in my entire Users database.
}match /user-compare/{anything=**} {
allow read: if true;
}
}
}
Ive tried
allow write: if request.auth.uid == userId && !request.resource.data.phone in resource.data.phone;
I want to make sure that a user can only read and write data inside its user ID, but my rules should be the one to prevent duplicate data not the source codes because due to the way the other system is setup, if multiple users have the same phone number, it will crash, and right now my app is the only way to make multiple users with the same phone number.
I know I can create a new collection to holder the numbers and then check if the number exist there for the registration process, but if anyone uses the other system to register, the numbers will not appear in this new collection.
The best way is if I can write a rule. My problem is a bit different from what I've seen and I hope I'm explaining properly. any help would be appreciated, thanks.
I couldn't solve it with rules no matter what I tried but Using Firebase Admin SDK will allow a developer write/edit/view information in Authentication section of the Service and this will allow you make the changes and validate them. You can learn more Here. This can be added as a dependency on the app but Due to the nature of the service I didn't feel that It'll be safe giving users access to an app with admin privileges. But this is a solution when you have the application for example in the office and users only have access to it in a save environment and can be used to add more functionality for staffs or authorized member's use.
For me, what solved my security concerns was to install the Admin SDK on a server. For my problem this can be used in two ways. I can make a custom authentication found Here and use that to sign in users using their phone number and password. But what I chose to do was make a simple API to take the phone number and check if there's any email address associated with it. if Yes retrieve the email and use that together with the password and sign in with email and password. so basically it uses the usual email and password sign in, but the user input their number and password instead. This was what worked for me and I hope it helped someone in a similar position.

Categories

Resources