2
votes

For our app we need to be able to offer groups access to files. Each user can have a large number of groups so it does not make sense to use the "custom token" solution (which is anyways very awkward.

As I discovered, Firebase is very limited with its Storage security rules. The main issue is that we keep Group definitions in Firestore which the Storage security rules do not have access to.

To overcome this we decided to include in the metadata of each uploaded file a "token" which anyone in the group has access to. When they download a file, they need to provide this token in the request params (e.g. /groups/xxx/filename.jpg?token=abc).

So I went ahead and wrote these rules:

match /groups/{groupId}/{filename} {
        allow read: if request.auth != null && request.params.token == resource.metadata.token;
        allow write: if request.auth.uid == userId
                    && request.resource.size < 1 * 1024 * 1024
                    && request.resource.contentType.matches('image/.*')
                    && (resource == null || request.resource.contentType == resource.contentType)
                    && imageId.size() < 32
     ;
}

But when I run it in the simulator I get the error: "Error: simulator.rules line [23], column [43]. Property params is undefined on object." which points to the rule with "request.params.token"

enter image description here

enter image description here

The documentation specifically states that we have access to the params object from the request object: https://firebase.google.com/docs/storage/security/secure-files?authuser=0#request_evaluation

enter image description here

2

2 Answers

1
votes

Due to the severe limitations of Firebase being able to query Firestore data in Storage and the incorrect documentation regarding request.param not being available, we had to use a different approach.

We decided to use the following URL when querying files of a group:

/groups/{groupId}/{token}/{filename}

The only security requirement is for the user to be logged in. Since the above token is a secret and only available to group members, we find it to be pretty secure. We do not allow listing of directories so it is not possible to simply list the /groups/{groupId} to find any tokens.

Note: another optimization could be to not include the {groupId} in the path but we felt it was better to include for debug and management purposes.

If anyone feels this is an insecure way, please let us know on the comments!

Thanks!

1
votes

It sounds like you're trying to proxy some data from Cloud Firestore into a Cloud Storage request for use in security rules. This is currently not feasible. (On top of that request.params currently refers to APIs that aren't documented, so it can't really be used. I've brought this up with the team, and we feel request.params should likely be removed from security rules docs.)

If you want to assign a Firebase Auth user some group identity that can be verified across products (Firestore, Storage, and Realtime Database), you can use custom claims for this. It will require some work on your backend to assign, directly to the user account, the value(s) you want to check. If you do it correctly, the values you set in that JSON blob will show up in request.auth.token in both Firestore and Storage security rules.