Deleting of an user is not preventing resource access - firebase

I am using Firebase Authentication to log in to my app and Firebase Storage to save some files.
The problem is that even I have defined such safety rules for storage:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth!=null;
}
}
}
When I delete or disable a user from Authentication Firebase manual panel then this user still can add and remove files to/from our storage.
With above rules I wanted to prevent a user to read/write when he/she is not authenticated.
According to documentation:
https://firebase.google.com/docs/auth/admin/manage-sessions
Refresh tokens expire only when one of the following occurs: - The user is deleted
In theory, it should work. Why it is not? And how to fix it, any idea?

Firebase Authentication uses ID tokens that are valid for one hour. Until the user's existing token expires, they can continue to use that token to access resources. But they won't be able to get a new ID token, so it will take no longer than an hour before they lose full access.
If this is not good enough for your scenario, you'll want to take additional measures to protect the files.
For data in the database, the documentation shows how to detect ID token revocation in security rule. But this approach won't work for Cloud Storage, as you can't perform a lookup of the revoked tokens in there.
For Cloud Storage you could implement your own API to control access to the files, where you'd then perform the same lookup of revoked tokens. That's the only way I can think of to implement immediate revocation.

Related

How do we secure a Firebase Firestore without using Firestore Authentication? Or is it a must?

At this moment we have 1 Firebase Function running that connects to a Firestore database instance. It correctly connects to the Firestore database using the rules below, however this is insecure.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
It is however unknown to me how we should secure this if we don't have Users in our application. It is not multitenant. We just do HTTP calls to the function and it saves something in the database.
To build user-based and role-based access systems that keep your users' data safe, use Firebase Authentication with Firebase Security Rules.
We do not have user data.
Note: The server client libraries bypass all Cloud Firestore Security Rules and instead authenticate through Google Application Default Credentials.
If we change our write rule to write: if request.auth() != null our application fails to save.
However, we can call getAuth() and then signInAnonymously(). But how does that make it more secure? And how long will the function remain authenticated?
We have read the documentation at https://firebase.google.com/docs/rules/rules-and-auth and https://firebase.google.com/docs/firestore/security/get-started. But as we don't have users in our application, it seems unclear to us how to secure Firestore using firestore.rules.
Concrete: How do we secure a Firebase Firestore without using Firestore Authentication? Or is it a must?
When not using Firebase Authentication, you cannot get details of user who is making the request. request.auth will be null in this case and hence request.auth() != null fails.
When you use signInAnonymously() the user is signed in with Firebase Auth and request.auth contains details of that user. However, once the user logs out of an anonymous account by any mean, there is no way to log back in with that account and user won't be able to access their data again.
If you use your own authentication method, using Cloud functions to retrieve data would be best so you can authenticate user using your auth system and then serve data if authorized.

Deleted user has access to Firebase Firestore

My application is a company-internal software. I want to enable all authenticated users to access all documents in the Firestore for tests.
I ran into a mistake while doing this.
The user logs in to the iOS app and has access to the documents.
I delete the user from Firebase Auth (via Firebase console)
As long as the user has the app open, he receives updates and can read and write.
Here is the code from the rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read : if request.auth != null
allow write: if request.auth != null
}
}
}
How can I prevent deleted users from continuing to have access?
The user logs in to the iOS app and has access to the documents.
That's the expected behavior.
I delete the user from Firebase Auth (via the console) As long as the user has the app open, he receives updates and can read and write.
When a user signs in with Firebase, he receives a token that is valid for about an hour. Unfortunately, such a token cannot be revoked, due to expensive checks on each call.
If you delete a user account right from the Firebase Console, the user can still have access for up to an hour. After that period of time, the token needs to be refreshed. But this operation will fail since that account doesn't exist anymore. So that access will automatically be disabled within an hour.
However, if you want to remove that access before the token expires, then you should consider keeping an additional list of banned UIDs and maintaining it over time. For instance, you can keep a global list/array of bannedUIDs into a document, and add the UID to that. Lastly, in your security rules, you can check if that particular UID is not banned. If that UID exists inside that list, then Firebase servers will reject the operation.
Edit:
Another option might be to disable the user account. This accomplishes the same as above and the user won't be able to get a new token after the current token expires. It also prevents the user from signing up again with the same credentials.

Is this Firebase/Firestore security rule for anonymously authenticated users safe?

I have a Flutter app that uses an API to pull data. My API key is the only thing stored in my entire Firestore database. My Flutter app retrieves the API key from Firestore and then uses it to fetch data.
My app also has anonymous authentication enabled. My app creates an anonymous user when the app is launched. My app does not allow users to create an account or sign up.
Below are the Firestore security rules that I currently have and I'm unsure if they can be improved to make them more secure from malicious attacks. My rules point to a very specific document myAPIKeyDocument, allows get only for authorized users, and does not allow write.
Are these rules safe as is or can they be improved if the only permission I want my app to grant is read access of my API key for anonymously authenticated users? And also, does if request.auth.uid != null; really make a difference at all since all users of my app will be automatically anonymously authenticated?
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /myDataCollection/myAPIKeyDocument {
allow get: if request.auth.uid != null;
allow write: if false;
}
}
}
If any user in your app having access to your API key is secure enough, then yes you are fine. Personally I would migrate any logic that requires an API key out of the client app and into Firebase Functions. That way you can more tightly control security to allow only requests from your app.
With anonymous authentication your current rules are about as good as it gets with the current structure of your project.

Why don't the firebase rules work when I do a kreait / firebase-php operation with the service account?

sorry for being naive. I'm a little confused about authentication with kreait/firebase-php package. I defined some rules at firebase console, like:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow create,delete:if request.auth.uid == true;
}
}
}
The problem is that, even if I change the rule, the behavior of the services(CRUD) will work the same way. It appears that the JSON document (service account downloaded from google) has all permissions or does not require firebase rules.
In my case, I want to restrict access and database operations to users where they don't have authentication and permissions.
I am currently checking the email / password. If the request is true, the method will return a token. After that, I persist the token in CACHE and delete it when the user logs out. With each request, the middleware checks whether the token exists in CACHE. That way, it will only help me to restrict the user's access pages. How do I restrict the operation of the database (CRUD)? Thank you all!
This behavior is expected. Access to Firestore coming from code initialized with a service account will always bypass security rules. Security rules only apply to access from the web and mobile client SDKs, and the REST API when provided with a Firebase Authentication token.

Firebase Auth, only activate account created after someone accept it

I currently have an website that uses firebase auth as my authentication. My problem is that I don't want to open registration to everyone, only a selected few people that are supposed to use the website. I read about .htaccess and .htpasswd but since I'm hosting on firebase hosting I don't think it's possible.
My question is how can I secure the account creation? I don't want to create the accounts manually at firebase console but have the users create it on a page. Is it possible to have the account work only after someone "accept" it at the firebase console or add an extra step after creation, can I somehow protect the registration page if using firebase hosting?
There is no way to prevent any user from creating an account after you enable Firebase Authentication. But the fact that they can create an account, does not necessarily mean that they can then use your application.
The typical approach for your use-case is to store a list of approved users somewhere. Since you're using Firebase Authentication, this would take the form of a list of UIDs.
So to be authorized to use your application a user needs to be authenticated, and approved. Firebase Authentication takes care of them being authenticated, and your back-end functionality should take care of checking their approval status.
For example, if you're using Cloud Firestore as your database, you'd store the approved user UIDs in a collection:
approvedUsers <collection>
UID1 <document>
UID2 <document>
And then you can check in the server-side security rules of your database that the user is authorized (authenticated and approved) before allowing them to (for example) read any data.
exists(/databases/$(database)/documents/$(document.reference))
service cloud.firestore {
match /databases/{database}/documents {
match /myCollection/{document} {
function isApproved() {
return exists(/databases/$(database)/documents/approvedUsers/$(request.auth.uid))
}
allow read, write: if isApproved();
}
}
}

Resources