I'm trying to serve an image hosted on Firebase Storage only to users that are logged in anonymously. Here is my storage rule:
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read: if request.auth.token.firebase.sign_in_provider == "anonymous";
}
}
}
But this doesn't work:
If I go to
https://firebasestorage.googleapis.com/v0/b/project.appspot.com/o/image.png (without the token in the url) it gives me 403
If I go to https://firebasestorage.googleapis.com/v0/b/project.appspot.com/o/image.png?token=tokenId it serves the image, but it serves it to anyone (logged, not logged, etc.)
Also tried with the default rule:
allow read: if request.auth != null;
Same thing. The simulator works fine but in production it just doesn't work. Am I forgetting anything here?
Thanks!
The second URL you show seems to be a download URL, which (by definition) give read-only access to the resource to anyone who has that URL. There is no way to protect access through security rules for download URLs.
The first URL only works when access through the Firebase SDK, or when you explicitly set up the Cloud Storage security on the bucket to allow public access, which would bypass Firebase security rules completely.
Firebase JavaScript SDK 9.5 just added methods to access the data through the SDK, so I recommend checking those out.
Related
I have an app that allows the user to upload images to Firebase Cloud Storage, stores the downloadUrl in Firestore DB, and read it (show it on the app) later on, using the downloadUrl, which includes the Access Token.
My cloud storage security rules restricts read / write to authenticated users only (as the sample here) but seems like anyone can access those images, outside of the app, by using the Access Token (via web browser for example).
So if someone gets the downloadUrl (stored in Firestore DB) he can access the images....
Am I missing something here?
How can I restrict access to those images from outside the app?
The download URL contains a download token which acts as a security measure to restrict access only to those who possess the token. The download token is created automatically whenever a file is uploaded to Cloud Storage for Firebase. It's a random UUIDv4, which makes the URL hard to guess.
There's no way that you can restrict that URL (not even through Firebase Storage Security Rules). It is always public. This is commonly known as a "public, unguessable URL". There is also a revoke option through the Firebase Console just in case the URL leaks.
The Security Rules will only apply to those URL that doesn't have the Access Token included e.g.: https://firebasestorage.googleapis.com/v0/b/<bucket>/o/<file>?alt=media.
If this URL will be accessed unauthenticated with these sample Security Rule applied:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
You will be given an error like this:
{
"error": {
"code": 403,
"message": "Permission denied."
}
}
However, As I pointed out, you don't need to be concerned about this URL (with access token) as in practice it is very hard to guess but if you don't want to store a shareable public URL (which is with the Access Token) then I would suggest using the Signed URL provided by Google Cloud Storage.
I am using firebase, react and react-native to develop an MVP app where users can upload image files and other users can retrieve them for viewing, and I am using firebase storage and the getDownloadURL() function.
I know that there are other ways of retrieving firebase storage files, but I want to use the downloadURL so that unauthenticated users may also view the images.
I know that downloadURL is public and access to files cannot be restricted even by firebase security rules.
Nonetheless, there is the revoke function where I can supposedly revoke the access token, i.e. the downloadURL. At the firebase console, I tried it out. It turns out that every time I revoke it, firebase generates a new one as replacement. More problematic is that I can still use the old (revoked) URL to access the image files. I checked out at the browser developer tool. The URL used by the browser was indeed the revoked URL. I used a new browser to ensure that the problem is not related to the cache. Even if I use a react-ative app, the same problem appears.
The image cannot be accessed only if I completely delete it from the firebase storage.
What is the problem here? Have I missed something?
I have looked up the firebase documentation and searched for similar issues on stackoverflow but cannot get an answer. Other people don't seem to have this problem.
The reason why you can still access the revoked urls is because in your firebase storage rules you have accepted reads for all users, whether authenticated or unauthenticated.
To prevent access to revoked urls, use the following in your firebase storage rules.
NB// This will require all users to be authenticated inorder to get the download url
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
I've got a simple firebase storage rule checking that only a logged-in user can access a doc:
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow write: if false;
}
match /{userId}/{filename} {
allow read: if request.auth.uid == userId;
}
}
}
However, I was surprised to find the storage url to the file can be opened even if a user if logged out and from a different browser where no user is logged in. What am I doing wrong?
If you're referring to download URLs that you generate with getDownloadUrl, then you're doing nothing wrong. They always provide full unauathenticated access to the underlying file, bypassing all security rules. If you need to protect the file with rules, then you should only provide the path to the file in the bucket, and make the client use the Firebase SDK to download it while signed in with Firebase Auth.
I have a simple firebase-react website, where users can register, sign in, and make post/delete requests to my firestore. I have the website hosted at Heroku and have a custom domain name. When I try to access my website however, the browser returns the following error:
This site can’t provide a secure connection
www.gigfort.nz sent an invalid response.
I recently changed the firestore rules to the following, to try and solve this issue - it however didn't work:
service cloud.firestore {
match /databases/{database}/documents {
// Allow public read access, but only content owners can write
match /some_collection/{document} {
allow read: if true
allow write: if request.auth != null && request.auth.uid == request.resource.data.author_uid
}
}
}
This code is form the firebase docs, and allows mixed private and public access.
So I'm wondering - am I right in assuming this issue is to do with my firestore rule set up, and if so, any suggestions on how to fix this?
It seems that your hosting provider is not provisioning an SSL certificate for the web site. It is accessible through HTTP, but not through HTTPS. I haven't set anything up on Heroku myself, but this link looks promising: https://devcenter.heroku.com/articles/ssl
As Doug commented, this error has nothing to do with your Firestore security rules. You'd have the same message accessing a static HTML page without any Firestore in it.
I am creating a Flutter mobile app and want to use Cloud Firestore to store some data that the clients should access. So far, there is no user-specific data, so I don't want my users to have to login in the app. What security rules do I need to specify to allow clients to read data, but deny public access (from "outside" of the app)?
These are the security rules I have setup so far.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow write: if false;
allow read: if request.auth.uid != null;
}
}
}
Under Authentication --> Sign-in method, I have enabled anonymous authentication. But I'm not sure if the security rules are correct and what Dart code I need in the client to get the desired behavior (no need for client to specify credentials, but protection of my data from access outside of the app).
so I don't want my users to have to login in the app.
But you authenticate them. Even if it's an anonymous authentication, it's still an authentication.
What security rules do I need to specify to allow clients to read data, but deny public access (from "outside" of the app)?
The exact rules you already have.
But I'm not sure if the security rules are correct.
The rules are correct.
what Dart code I need in the client to get the desired behavior (no need for client to specify credentials, but protection of my data from access outside of the app).
Your code should look similar to this.