firebase storage bucket and Fastly CDN integration - firebase

In order for me to get Fastly working with firebase storage I had to add the following permissions on each image and the storage bucket: Entity: User, Name: AllUsers, Access: Reader. Is there a way to avoid this tedious and unscalable method, since its all user uploaded media?
My firebase storage security looks like the following:
service firebase.storage {
match /b/myapp.appspot.com/o {
match /proUsers/{userId}/{allPaths=**} {
allow read, write: if request.auth.uid == userId || request.resource.size < 2 * 1024 * 1024 || request.resource.contentType.matches('image/png') || request.resource.contentType.matches('image/jpeg');
}
}
}
the error I receive on fastly is that: Anonymous users does not have storage.objects.list access to bucket and if I try to access image directly I get the error: Anonymous users does not have storage.objects.get access to object
Where do I allow for anonymous users to have read capabilities? I assumed setting allow read did precisely this.

To allow anonymous users to read from your database (but not write) you can change your rules to this:
service firebase.storage {
match /b/myapp.appspot.com/o {
match /proUsers/{userId}/{allPaths=**} {
allow write: if request.auth.uid == userId || request.resource.size < 2 * 1024 * 1024 || request.resource.contentType.matches('image/png') || request.resource.contentType.matches('image/jpeg');
allow read;
}
}
}

Related

Firebase, insecure rules

I recently received an email from firebase telling me that the rules of my database (Firestore) are insecure so I changed them to the following:
rules_version = '2';
service cloud.firestore {
match / databases / {database} / documents {
match / {document = **} {
allow read: if true;
allow write: if request.auth.uid != null;
}
}
}
Before I had these rules:
allow read, write: if true;
After making the change, the emails keep coming back and I don't know what else to do.
I already tried several of the following options given in this link but none of them works for what I need.
https://firebase.google.com/docs/rules/insecure-rules#firestore
I need authenified users to be able to read and create content. So use the rules that I put above.
I saw that in the email they send me it says that people can modify my database, is this referring to from the app, or does it mean that they can hack me or something?
Because the end of my app is that users can create content.
But I don't want someone to hack into my database and delete everything, is that possible?
Thanks
The emails are because the rules aren't really stringent. You should probably be using the following rule, that:
Allows unauthenticate users to read data
Allows authenticated users to create entries
Allows to update & delete entries that are only owned by themselves and not of others.
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 create: if request.auth.uid == request.resource.data.author_uid;
allow update, delete: if request.auth.uid == resource.data.author_uid;
}
}
}
Read this article for better understanding. You can also check when firestore flags rules as insecure over here. More importantly, this is the point to be emphasized.
Remember that Firebase allows clients direct access to your data, and
Firebase Security Rules are the only safeguard blocking access for
malicious users. Defining rules separately from product logic has a
number of advantages: clients aren't responsible for enforcing
security, buggy implementations will not compromise your data, and
most importantly, you're not relying on an intermediary server to
protect data from the world.
Sample rules:
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userDoc} {
allow read: if true
allow create: if request.auth.uid == request.resource.data.id;
allow update, delete: if request.auth.uid == resource.data.id;
}
match /posts/{postDoc} {
allow read: if true
allow create: if request.auth.uid != null;
allow update, delete: if request.auth.uid == resource.data.user_id;
}
match /comments/{commentDoc} {
allow read: if true
allow create: if request.auth.uid != null;
allow update, delete: if request.auth.uid == resource.data.user_id;
}
}
}
This case is mentioned in the documentation. Any authenticated user can write to your database and that also involves deleting data. You are using a recursive wildcard which gives them access to complete database.
Instead try rules that allow users to write their own documents only or something similar.
rules_version = '2';
service cloud.firestore {
match / databases / {database} / documents {
match /collectionName/{docId} {
allow read: if true;
allow write: if request.auth != null && request.auth.uid == docId;
}
}
}
Above example will allow users to edit documents where document ID is equal to their UID only.
If you wish to allow selected users to write (such as admin) then you can add a field namely admin and set it to true in user's document in users collection. Then you can read the document data as shown:
match /collection/{document} {
allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true;
allow read: true;
}

Firebase storage rules: authenticate the allowed user

I have a channel for communication between two users and I use Firebase storage to transfer files between these users.
I don't want a third user to have access to the channel's files.
I'm trying to identify authorized users using 'authfile' and the metadata inside it.
That authfile is uploaded using admin sdk.
Only specific users can download and upload files to specific path in storage where the authfiles metadata contains his uid. still the users are not allowed to touch the authfile.
The metadata inside the authfile looks like this:
metadata: {
AvnYaUFdaJh1j0FMIiKWoIC2MDw1: true, // firebase userId 1
YhFyYRbutlf1PFI4NLKTN4qWRhQ2: true, // firebase userId 2
}
my storage
The rules I've tried:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
// Channel Media
match /media/{channelId}/{allPaths=**} {
function isAllowedUser(uid) {
return /authfile.resource.metadata.users[uid] == true;
}
allow delete: if isAllowedUser(request.auth.uid)
&& request.resource.contentType != 'authfile'
allow read: if isAllowedUser(request.auth.uid)
&& request.resource.contentType != 'authfile'
allow write: if isAllowedUser(request.auth.uid)
&& request.resource.contentType != 'authfile'
&& request.resource.size < 16 * 1024 * 1024;
}
}
}
I am writing Firebase storage rules for the first time and would like advice on how this could be implemented.
I don't think you need 'users' here.
function isAllowedUser(uid) {
return /authfile.resource.metadata.users[uid] == true;
}
This should be valid
resource.metadata[uid] == true;
Additionally, if you need something like checking existence of another file or it's metadata, consider using Cloud functions as mentioned in this answer.

why I can still open my image stored in Firebase storage via browser even though it has rules?

so I have security rules like this:
service firebase.storage {
match /b/{bucket}/o {
match /eventPoster/{imageID} {
allow read: if isSignedIn()
allow create: if isSignedIn() && isImage() && lessThanNMegabytes(0.5)
}
function isSignedIn() {
return request.auth != null;
}
function isBelongTo(userId) {
return request.auth.uid == userId;
}
function lessThanNMegabytes(n) {
return request.resource.size < n * 1024 * 1024;
}
function isImage() {
return request.resource.contentType.matches('image/.*');
}
}
}
as you can see, I set only signed in user that can see/read the image. but if I copy and paste the link from my file in storage like below in incognito browser, I still can see my image
https://firebasestorage.googleapis.com/v0/b/XXXXXXX.appspot.com/o/eventPoster%2F0050370e-a226-4a69-a635-ceccce10007c?alt=media&token=44f6d5a4-ff44-4376-3c7b9dfac465
I expect that I can't see the image via the browser, I test it using google chrome. even though my app is for Android and iOS just for testing I use browser. I assume, I am not signed in if I access it via the browser
The URL you shared there is a download URL. That URL is publicly readable, regardless of security rules. The only way to stop it from working is by revoking its token from the Firebase console.
If you want a file in Firebase Storage to only be accessible in accordance to its security rules, don't generate download URLs for it, or at least don't share the download URL with anyone.

Cloud Firestore - still get "any user can write to your entire database" error

I've added rules to my Cloud Firestore database but still receive these issue messages:
any user can read your entire database
any user can write to your entire database
See the rules below.
Indeed, any user can read and write into "users" collection, otherwise I won't be able to log in/register a user. How to solve the issue?
Thanks
The problem with your current rules is that it allows any user to read/write any other user's user document. You need to restrict it a bit more to look at the userId of the documents. Something like this
service cloud.firestore {
match /databases/{database}/documents {
// Ensure the user is authenticated
function userIsAuthenticated() {
return request.auth != null && request.auth.uid != null
}
// Ensure the user owns the existing resource
function userOwnsResource() {
return userIsAuthenticated() && request.auth.uid == resource.data.userId
}
// Ensure the user owns the new resource
function userOwnsNewResource() {
return userIsAuthenticated() && request.auth.uid == request.resource.data.userId
}
match /users/{userId=**} {
allow read, update, delete: if userOwnsResource();
allow create: if userOwnsNewResource();
}
}
}
userOwnsResource checks that the user can access an existing resource. userOwnsNewResource checks that they can create a new document for their userId. You can obviously reuse these functions in other rules which is handy.

Firebase storage size limits not enforced

Hello I have rules for the folder /posts/media/{userId}/{media} like the following:
service firebase.storage {
match /b/{bucket}/o {
match /{allPath=**} {
allow read, create, write;
}
match /posts/media {
allow create: if request.auth != null && request.resource.size < 10 * 1024 * 1024
&& request.resource.contentType.matches('(image|video)/.*');
match /{userId}/{allPaths=**} {
allow create, write: if request.auth.uid == userId && request.resource.size < 10 * 1024 * 1024
&& request.resource.contentType.matches('(image|video)/.*');
}
}
}
}
The file size of 10MB is not enforced. Users can easily post videos of several times the limit of 10MB.
Any help?
Thank you,
Michel
This rules is allowing unrestricted read and write access to your entire storage bucket:
match /{allPath=**} {
allow read, create, write;
}
If you don't want that behavior, then remove that rule. Its permissiveness is going to override all other rules. You can't narrow the scope of access granted by another rule. If any rule allows access to a file, that can't be changed by another rule.

Resources