Reading firebase storage image security rules - firebase

I am using Firebase storage and firestore with flutter,
I came across two options to retrieve Firebase storage image
Setting Firebase storage image url in firestore database and then fetching it with network image
Getting image url from Firebase storage directly
I don't know much about tokens.
My security rules states that only auth users can read my Firebase storage but if I use first option my image url with token is stored in my firestore database using that url anyone can access my storage. I am not sure does Firebase refresh it's storage token automatically then if this is the case my app will experience crash.
Which is the most secure and long lasting way or please answer if any other secure way to fetch images

Firebase storage tokens won't expire unless you revoke them. The token may update if you overwrite the image i.e. update it. Now that's totally your call if you would like to make a separate request just to get the download URL or store the URL in realtime database when an image is uploaded and fetch it along with other data.
Security rules of Firebase Storage will prevent non-authenticated users from getting the download URL only. If an authenticated user shares the URL with anyone, they will be able to see the image as they have the URL with that random token now.
If the data you are fetching from realtime database requires the user to be logged in at first place, then I'd just store the URL in the database itself as I don't think it makes sense to make another request and have the same rules for Firebase storage. I don't know your exact use case so there may be exceptions for doing this.
If you don't need that image URL always then that might be waste of bandwidth, then you should consider making separate request to get the storage URLs.
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
These rules will allow any authenticated user to request the URL. But as I mentioned earlier, anyone with this link can access the file.

Related

Which Google Cloud services should I bundle to add online storage support to my desktop application?

I am writing an Electron app (built with Angular) and I am conducting research on how to add online cloud storage support to my desktop application?
The user shall be able...
to login into their account
to upload/download their own files to an online storage/drive.
The user shall basically be able to login into their account and upload and download their own files through the app.
Question 1
Does a combination of Firebase Authentication + Firestore Storage sound like a proper solution for this requirement? Is there any limitation of these two services that might not work for this?
Question 2
I have a related but different question posted here
Firebase storage is useful when it comes to user generated content. In fact, the description in the documentation says that,
Cloud Storage for Firebase is built for app developers who need to store and serve user-generated content, such as photos or videos.
You can create a folders with users' UIDs as the key to restrict users to their own files:
service firebase.storage {
match /b/{bucket}/o {
match /users/{uid}/{files=**} {
allow read, write: if request.auth != null && request.auth.uid == uid;
}
}
}
Do note that security rules only prevent users from fetching the file's download URL themselves. If a user (UID123) shares the link to one of their file to someone else (maybe unauthenticated), they still access view the file as they now have the URL with the access token. I've explained that in this answer as well.
These download URLs never expire unless the token is revoked.
If you want to prevent URLs being used for longer duration, you can generated signed URLs. Anyone can still use these to view the files (if the user shares it) but you can set the expiration time on signed URLs.

Firebase Security Open Access

My android wallpaper app is connected to Firebase Cloud Firestore. It doesn't have any user authentication because I want the user to be able to use it without fuss. To do this, it must be in open access, meaning, the user is allowed to read and write. This is dangerous as he can also edit and modify the data if he knows the project id. The project id is visible in the url of the app so this is not really a good choice. Closed access is also not an option for obvious reasons.
Is there anything I can do to protect my data without need of a user authentication? I would love to see the code needed for the Cloud Firestore and Storage to protect the data. I want the user to read only and I, as the owner, should be the only one who could write. Please refer to the images attached. Thanks a lot for taking time to answer my questions.
My data structure in Firebase Cloud Firestore:
Securing your data with Security Rules
Firebase Cloud Firestore, Firebase Realtime Database and Firebase Cloud Storage are secured by their own Security Rules. They provide access control and data validation in a simple yet expressive format and allow you to control access to documents and collections in your database.
To build user-based and role-based access systems that keep your users' data safe, you need to use Firebase Authentication with Cloud Firestore Security Rules.
Your specific use case
I assume that you store your data in Firebase Cloud Firestore and the wallpapers in Firebase Cloud Storage. The user then gets a document with a link to download a wallpaper and maybe also can upload their own wallpapers to the database.
The dangers of an open database
As you mentioned allowing all reads and writes to your database in a production app is very dangerous. Obviously, anyone with your database reference will be able to read or write data to your database. Unauthorized users could destroy your backend and there are also possibilities that costs could increase exponentially. Therefore this is not recommended. There always should be some mechanisms preventing these scenarios.
Recommendation: Using anonymous authentication first and connect later with existing Identity Providers
I recommend that you use Firebase Authentication to create and use temporary anonymous accounts to authenticate with Firebase. These temporary anonymous accounts can be used to allow users who haven't yet signed up to your app to work with data protected by security rules while not being in the way of your user experience. If an anonymous user later decides to sign up to your app, you can link their sign-in credentials to the anonymous account so that they can continue to work with their protected data in future sessions.
You could also enable Google-Sign-In, Facebook Login, Twitter, GitHub, Microsoft, Yahoo, etc. to let users authenticate in a very fast and easy way without compromising on a security standpoint if using regular password authentication is not what you want (from a UX standpoint). FirebaseUI makes it really easy to add these to your existing app. Check out the official documentation on this topic.
Implementing Cloud Firestore Security Rules
The official documentation on this is really great on how to get started with Cloud Firestore Security Rules.
However these security rules could work for you:
Allow read access to all users to the root (Not recommended because this can create huge costs in production). Users don't have write (create, update, delete) access. In this case you can edit your data via the Firebase Console. Choose either option 1 or option 2 for your project.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Option 1: Matches any document in the 'root' collection.
match /root/{rumiXYZ} {
allow read: if true;
allow write: if false;
}
// Option 2: Matches any document in the 'root' collection or subcollections.
match /root/{document=**} {
allow read: if true;
allow write: if false;
}
}
}
The {document=**} path in the rules above can be used to match any document in the collection/subcollections or in the entire database. This should however not be necessary for your use case. Continue on to the guide for structuring security rules to learn how to match specific data paths and work with hierarchical data.
Don't forget to secure your Firebase Cloud Storage too!

How to restrict firebase storage files only for the paid user?

I have the file stored in firebase cloud storage. This file will only available for the paid user download.
How to set up security rules to allow the paid user to have read access to that file?
[Updated]
I use the cloud firestore to store user collection
Each user doc contain
uid
email
name
photoUrl
provider
status
stripeCustomerId
purchasedProducts << this is the array of product name
I can verify paid user by looking if the product exist in purchasedProducts array.
However, inside the security rule from Firebase storage, it seem I can't access resource (user collection) in there. Or am I missing something?
Thanks
There is no way to access Cloud Firestore from within the security rules for Firebase Storage.
That means the only ways to currently implement your use-case is to:
include the necessary information in the ID token of the user, as a custom claim, which is then also available in security rules.
include the necessary information about the user (probably their UID) in your security rules
Since the second approach requires that you update your rules for every paying user, it's not very common.
Setting a custom claim can be done through the Firebase Admin SDK, for example from a Cloud Function that triggers when you write their payment information to Cloud Firestore.
Once you set the custom claim it may take up to an hour before it's available on the client, and from there in the security rules. The reason for that is that the claims are included in the ID token, which only auth-refreshes once an hour. If you want to get the updated claims sooner, you can force a refresh of the user's profile on the client.
Another approach you can try is to delete a file right after it was uploaded using the functions.storage.object().onFinalize webhook - this is wehere you can access the database and check if the user was allowed to upload the file.
Even though it may look a bit 'hacky' at the first glance, this is really a precaution measure in the first place - the UI itself would restrict the upload for the "good" users. And for those who messes up with the source code and tries to circumvent the system, onFinalize would do the job.
You can access cloud firestore through the firestorage service security rules:
https://firebase.google.com/docs/storage/security/rules-conditions#enhance_with_firestore

Trying to make app secure with API key, but it isn't being used

I've created a web application that displays data from my cloud firestore. I'm about to release it to the public, but I don't want just anyone to be able to read/write to my database.
I have currently restricted my API key to only allow requests from my website's url, but it doesn't seem to be doing anything. I've even deleted it from the app entirely and it is still able to access the database.
Is there a rule I need to set up in my firestore to make it require an API key? I've googled plenty of things, but all I can find are articles on why it's ok to have your key be available to the public.
It's not possible to restrict access to Firestore based on some plaintext API key or web site domain. If you're publishing an app that provides direct access to Cloud Firestore (or Cloud Storage, or Realtime Database), the only way to secure it is with a combination of Firebase Authentication and security rules. The security rules allow you to express who can read and write which collections and document.
If you aren't using Firebase Authentication, and your default security rules allow universal read/write access, then anyone with an internet connection will be able to read and write every document.
A slight variation on Doug's excellent answer is to allow all users to write to specific documents that pre-exist and that have impossible to guess names. These document names then essentially become your own API keys, that you share (out of band) with the users of your app.
The security rules for this can be as simple as:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow create: if false;
allow update: if exists(resource['__name__']);
allow get: if true;
allow list: if false;
}
}
}
So: anyone can get/update any existing document that they know the name of, but they can't create a document, nor get a list of all documents.
This prevents the need for using Firebase Authentication. On the other hand it means you can't lock down access on a per user basis. Any user that somehow gets access to the document name, can now read/write it at will.

Firebase Storage Security Rule : Check if another object exists / check object's metadata

In Firebase storage security rules (not realtime database), is there any way to perform a check if another object exists at path, or another object's metadata exists?
Some background
Currently my storage security rules are set up so that users only have read access, and not write access to their /users/{userId}/ paths.
I have an admin cloud function that saves a file to /users/{userId}/necessary-file.pdf. And I don't want users to be able to modify or write this file and only cloud functions to have the right to do. To achieve this I think I can match for the filename like :
match /users/{userId}/{fileName} {
allow write: if !fileName.matches("necessary-file.pdf")
}
Question
Is there any way for me to only allow users to write some-other-file.pdf if they already have a necessary-file.pdf at the same path (or even somewhere else if that works better). All while still disallowing them to write necessary-file.pdf.
So is there any way for me to do something like this pseudo-code? :
match /users/{userId}/{fileName} {
allow read: if request.auth.uid == userId;
allow write: if (!fileName.matches("necessary-file.pdf")) && ("necessary-file.pdf".exists())
}
As an alternative, I can have my cloud functions write a metadata to necessary-file.pdf and check for that too. is there any way I can perform something like this pseudo-code? :
allow write: if "necessary-file.pdf".metadata['canUserWrite'] == 'yesUserCan'
Finally
What's really cool about this is that, if this is in any way remotely possible, it can be used to communicate between firebase database and firebase storage rules in a not-so-realtime way. (referring to this question here) A cloud function can listen for changes in the intended field in realtime database, and write a file to firebase storage, which firebase storage can check for.
Firebase's Cloud Storage security rules can only access information about the current request and file. They don't have access to the full storage system, so can't check whether another file is present.
The reason for this is that the rules are evaluated in memory for every request. Providing access to Cloud Storage for other objects would slow the performance down, making the system unscalable. That same reason explains why you can't access the Firebase Database from the security rules.
If you want some control like this, you'll want to look in Cloud Functions for Firebase. If you have your users upload their files into a "staging" area, you can have a Cloud Function validate whether they met all prerequisites and only then move the file into the actual location (making it available for further processing or for clients to see).
(Another Solution) Restricting Storage Access with Auth Claims
Cloud Storage Rules has access to auth info for the request user. By setting up a check during the authorization process an auth property can be added for later access validation in storage rules.
Original Question:
Is there any way for me to only allow users to write
some-other-file.pdf if they already have a necessary-file.pdf at the
same path (or even somewhere else if that works better). All while
still disallowing them to write necessary-file.pdf.
Yes, this could be done by checking an auth.token.
Example flow for a Web App w/ Google Signin:
Create a Cloud Function to set a custom claim that checks for the existence of that file against the current auth user.
Upon success of the user authorizing via Google call that cloud function for it to set a value to the auth object.
Check auth.token in the storage rule.
Web Example for Custom Claims:
https://firebase.google.com/docs/auth/admin/custom-claims?hl=ro#examples_and_use_cases
Example Storage Rule:
https://firebase.google.com/docs/storage/security/rules-conditions?hl=ro#group_private

Resources