I have an android app which uses firebase for authentication and firestore for storing user data. Once the authentication is complete for a first time user, we collect extra info like nick name, age etc and store them in Firestore. We also have an important field called USER_BALANCE. This is set to 0 on new account creation. How can i make sure they dont manipulate this field.
int USER_BALANCE = 0;
User user = new User(name, email, USER_BALANCE,0,0, refreshedToken); db.collection(FIREBASE_COLLECTION_USERS).document(firebaseUser.getUid()).set(user).addOnSuccessListener(this);
We also have certain task in app,on completion where user gets rewarded and points will be added to USER_BALANCE in firestore. I want to make sure nobody decompile the app and can update the field with whatever value they want.
You can use firebase rules for that. Firebase rules check if a user is able to manipulate your data. You can choose for the user to be able to only read the specific value. Because you haven't provided a view of your database structure I haven't tell you how the specific rule that you need will be framed. Check this blog it really helped me a lot when I was starting.
---Edit---
The below firebase rule checks if the user tries to update the specific field and blocks it. You can check this post for more information.
function notUpdating(field) {
return !(field in request.resource.data)
|| resource.data[field] == request.resource.data[field]
}
match /Users/{userId}{
allow read;
allow update: notUpdating('user_balance');
}
Anybody can decompile the app and attempt to make changes. There is no way to prevent that. They don't even need your app to write the database, since it has a public REST API.
What you will need to do instead is use Firebase Authentication along with security rules to determine who can read and write which documents. There is no other way to control access to your database if you intend for your app to be able to read and write it directly. If you can certainly disable public access entirely and create your own backend - but you have just shifted the responsibility onto the backend for making sure the API it exposes also does not allow arbitrary callers to make unauthorized changes.
Related
So I am creating an Android application in which suppose there are 2 user types, userType1 & userType2. Now what I want is that only userType1 will see and be able to access the post button, and userType2 Can't see and or access it. So what is the best practice for that?
The best practice would be to implement Firebase Authentication and save user data, either in Cloud Firestore or in the Realtime Database together with the user type. When you start the app, first you have to read the user type and then display the UI elements according to it. I have answered a question in which I have explained how to redirect the user according to its type to the corresponding activity. Here is how you can do that using Cloud Firestore:
How to redirect a user to a specific activity in Cloud Firestore?
Or using the Firebase Realtime Database:
How to redirect multiple types of users to their respective Activities?
The same mechanism can be used to hide/display a button. Don't also forget to secure your data using security rules.
I wanna ask about the concept and logically ways to give another user the privilege to access other's users' data. What I want to do exactly is like this :
Basically, collection 1 contains several Users ID (UID) from authentication, then the user will have their own data collected in collection 2 which contain the data ID.
So, it's like giving access to another user to collaborate with the data like Google Docs Apps where we can add another user to edit our documents. I've been thinking of how to do this, but still, I got stuck.
My question is, how can I possibly do this? cause from what I've read, cloud firestore don't use such a foreign key like MySQL. Thank You
haven't tried something like this but i think this approch overcomes your problem.
modify your structure according to above image. userID collection will contain userIds which are allowed to edit their parent collection.and create firestore rules according to your use to check weather the userId is allowed to edit the Collection or not.
in your case when 'user 2' will have reference to 'collection 2', he/she will try to change data. firebase rule will check if auth.userId is inside the 'collection2.UserIDs' or not and will allow according that.
I am struggling to find a solution to prevent clients from just creating random fields with values in a document where they have write access to in Firestore. Since you cannot restrict access to single fields in Firestore like you could with the realtime database, this seems hard to achieve.
A solution would maybe be to not allow creation of fields and just letting clients update fields, but this would mean you would have to precreate the fields for documents which is not really a good solution in my opinion, especially if you have documents per user, which are dynamically created and having to use cloud functions to precreate fields in a document just seems unjustified.
Does anyone have a better solution?
As said in the Firebase Firestore documentation, you actually can prevent or allow writes or reads in certain fields. This can be achieved by adding a rule similar to this:
match /collection/{doc} {
allow update: if request.resource.data.field == resource.data.field;
}
Which would basically check if that specific field will have the exact same value after the update. You can also add rules to check if the requested value is between a range or equals to (your predefined value).
allow update: if request.resource.data.field > 0 && request.resource.data.field > 100;
You can inspect the keys of the request.resource and only have it pass if it doesn't contain a field that you want to keep read-only (meaning that the request isn't trying to update that field). For example:
allow update: if !request.resource.data.keys().hasAny(['my_field'])
(Thanks to James Qualls for the inspiration!)
This is a pretty basic question and I'm surprised that the Firebase guides don't cover it. In their own example of registering a user, the code seems very inefficient unless there is some built-in optimization I'm unaware of. It seems each time you log in, you will also push the user data to firebase.
ref.authWithPassword("jenny#example.com", "correcthorsebatterystaple",
new Firebase.AuthResultHandler() {
#Override
public void onAuthenticated(AuthData authData) {
// Authentication just completed successfully :)
// irrelevant: some code to construct userData
ref.child("users").child(authData.getUid()).setValue(userData);
}
#Override
public void onAuthenticationError(FirebaseError error) {
// Something went wrong :(
}
});
1) There appear to be no checks if a user already exists at that location and if the data we are attempting to persist is different. How would one accomplish that? Would you need to first read the fields, check if different and then attempt to update (all of this in a transaction)?
2) If I'm right about (1), would you recommend storing some indicative data locally to short-circuit the need to "check" with firebase if the user is registered? I could store a boolean + a local copy of the user so I can (A) check the registered boolean and if true, then (B) check if the local user data is the same. If both are true, I can completely skip step (1) above.
Obviously I want to avoid any caching logic in app space due to the usual complexity cost. Does Firebase guarantee super fast local-only queries (what I'd do in (1)) if the data hasn't been changed? I want to avoid extra client logic as much as possible.
Thank you.
You may overestimate how often authWithPassword() runs. In a well-implemented Firebase app, you will use an onAuth() listener to detect when a user has previously signed in. So you'll only need to actively authenticate them when their session has expired or otherwise has become invalid.
If you'd prefer to only write the user's profile data when they first sign-up, you can do the same logic when you call ref.createUser().
To know client-side whether the data is the same, you'd indeed first have to read it. Which negates any positive effect you might gain by not writing it.
The set-up:
I have an android application that so far can register a user by inserting values into a remote mysql database. I'm now trying to implement the log in.
I was thinking that I can add a "logged in" column to the user table in the database that would store whether or not the user was logged in. Then I would have a trigger that would log the user off after a certain amount of time has been elapsed.
The application's use is to retrieve files based upon if the user has access to a certain file. For this I have an "access" column in the user table table specifying the access a user has to a certain file. I was thinking that when a user clicks an item in a list the application would send their login information and the server would determine if the information was correct then check to see if they had access to the specified file then send back the file if the information is correct.
The problem I'm having though is that checking the registration information takes about 2 seconds alone(due to connecting to the socket and sending a string over the network) and if I try to check both the login and the access id it would take slightly longer.
I feel as if I'm trying to reinvent the wheel but I can't find any viable resources on this matter. Criticisms? Suggestions?
(I wouldn't mind doing a complete redesign I just need to know where to start)
Never connect a client to a db-server. There's no way to intercept hacking attempts, because privileges are very basic (SELECT, UPDATE, etc., they ignore the query):
UPDATE users SET name='%s' WHERE userID=%i // where %i will be defined as the real userID
Above should be a valid query to update the user's account-information, however, a hacker can easily intercept this and change it into:
UPDATE users SET name='%s' WHERE userID=15 // ... or any other variable
Instead, you should create a web based API which will validate each query, or better, support only specific API-commands:
account/update.json?name=%s