Revoking Firebase storage download urls

5,846 views
Skip to first unread message

Mitch Grasso

unread,
May 20, 2016, 11:53:14 PM5/20/16
to Firebase Google Group
The security available for getting the url is great but I'd like to be able to manage the life of the url as well. 

I see in the console UI that i can manually revoke the download URL for a file but there doesn't seem to be an API call to perform this action nor can you set the timeout of the URL in getDownloadURL().

What is the best practice for securing download urls? 

thanks

Mike Mcdonald

unread,
May 21, 2016, 7:49:36 PM5/21/16
to Firebase Google Group
Hi Mitch,

Excellent questions--I think I'll have to update the docs to clarify this further.

There are two ways of downloading files from Firebase Storage:
  • Using the public, unguessable https:// URL
  • Using the private, local gs:// URL
The public URL was designed for easily sharing content (think Google Photos or chat apps that let you drop an arbitrary image into the feed), since these URLs don't require authentication or authorization checks. These URLs are great for sharing content from your app outside of the app, but can be revoked if the URL leaks too widely.

Since we anticipate that revocation is something that the developer will be the person revoking, not necessarily the app user, that's why the revocation comes through the console. In the future, we may offer signed URL creation/revocation through the Firebase CLI to simplify this process, though no idea on the timeline for this.

The private URL is designed to be the highest security mechanism: all download calls (or public URL creation calls) are guarded by Firebase Storage Security Rules, which can have developer specified expressions. You can validate that the user is who they claim to be, as well as create a timeout on the expiration (or even mandate that the file can only be viewed once).

service firebase.storage {
  match
/b/<your-bucket>/o {
    match /
{imageId} {
     
/* Allow a read if the file was created less than one hour ago */
     allow read: if request.time < resource.createdAt + duration.value(1, 'h');
   }
 
}
}

Since we provide such flexibility in the private URLs, we opted for a simpler solution for public URLs. I'd love to hear if you think that this distinction is reasonable, or if there are cases where you want to use public, expiring URLs where the private URLs don't work.

Thanks,
--Mike

Mitch Grasso

unread,
May 22, 2016, 7:31:52 PM5/22/16
to Firebase Google Group
Hi Mike,

It's unclear to me from the docs how you can download a file using a gs:// URL from a web app using javascript. Is this perhaps only possible from ios/android?

My use case is enabling a user to share access to a document that contains images and I'm concerned about the removing access to the image URLs if the user decides to unshare the document. On the AWS stack, i'd generate short-lived signed URLs everytime someone viewed the shared document but I'm not clear how to reproduce this behavior using firebase because once they viewed the document they'd have permanent access to the image URLs even if the document had been unshared. It seems like an interesting solution would be to be able to revoke the image urls through the API so, if the document owner unshares the document, all it's download urls are revoked. 

BTW, the getDownloadURL() documentation states that the url is "long-lived". How long is that?

thanks!
Mitch

Mike Mcdonald

unread,
May 23, 2016, 12:19:05 PM5/23/16
to Firebase Google Group
Mitch,

Unlike Android and iOS where you can download a file into memory or a local file system, downloading a file in Javascript is effectively up to the browser and the headers on the file you're downloading. What you need to do is convert the gs:// URL to an https:// URL via the getDownloadURL() method, and then use this https:// URL to stick your image in an img tag (or similar) to "download" it. These https:// URLs are permanent (long lived == infinity ;) but revokable, so if one of them leaks, you can revoke it from your Firebase Console under the Storage section's file viewer.

Moving into your question: once you're using gs:// URLs, the best way to do this is to store them in a database (like the Firebase Realtime Database) and retrieve that list, then implement revokable user based file access via Firebase Storage Security Rules (examples of this are in the docs). That would mean that only specific users can get the download URL and view the file.

A quick note on security: since it can safely be assumed that if a user has been able to view a URL once, it's reasonable that they've downloaded it and revoking the URL doesn't do anything (except prevent other people from viewing it, which we already allow for in the console and with security rules).

Thanks,
--Mike

Mitch Grasso

unread,
May 23, 2016, 2:34:12 PM5/23/16
to fireba...@googlegroups.com
Hi Mike,

Thanks for your responses! I absolutely get that revoking access to content is ultimately impossible in the web stack (since once you have it, you can extract it) and it was mostly about mitigating (perhaps uneducated) potential customer concerns about security. I’d still like to put my vote in for the ability to revoke the URLs through the storage API though :-)

thanks
Mitch


-- 
You received this message because you are subscribed to a topic in the Google Groups "Firebase Google Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/firebase-talk/aw86jf8b7PY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to firebase-tal...@googlegroups.com.
To post to this group, send email to fireba...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/firebase-talk/6146f18b-2959-45b6-9f7c-7ed3aae44e00%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

frank polkm

unread,
Sep 25, 2016, 5:49:29 PM9/25/16
to Firebase Google Group
Totally agree with Mitch, waiting for the API available. And my suggestion is Firebase accept current user session token as the download URL token. That means I can save the download URL in database without token. When I prepare the download URL, I will append current user session token to the URL. Firebase check storage role based on the user session token to determine if allowed just like database.

Thanks,
Frank

Mike Mcdonald

unread,
Sep 25, 2016, 7:12:38 PM9/25/16
to Firebase Google Group
Hi Frank,

We actually thought of that--it's equivalent to doing ?auth=<JWT> at the end of the request. That said, this feature is nearly identical to the feature we've already implemented: downloading directly from the API without generating a download URL. The odd thing is that in browser JS land, "downloading" is different concept in that you end up having to create a public URL in order to download the file. As said above though, being able to revoke a token is pretty pointless from a security standpoint, since if a user has already had access to the file once, we can assume that they've already saved it/their browser has cached it, and revoking the token just stops it from spreading. To be clear, it's not that this isn't a good thing, it's just that whatever information can still be spread, albeit not as easily.

The trickier aspect of this API is, "what permissions are required to revoke a download token?" Do we have to add a new parameter to our security rules that reads "allow revoke: if..." or is this only available via some other credential (like the developer's Google OAuth credential)? Is it acceptable to allow regular end users to revoke tokens? Probably not, since a single rogue user could ruin an app for everyone by revoking all tokens.

So the short answer is: we hear you, but we think that we've already provided good enough mechanisms for a majority of use cases. And for those we haven't, you can generate a signed (expiring) URL via Google Cloud Storage's APIs (using developer credentials) and distribute those to end users, so their access will expire after a certain time. And if you're still struggling with a use case that can't be solved by either 1) proxying bytes directly to the end user, 2) long lived, but revokable URLs, or 3) short term expiring URLs (via GCS), respond on this thread with a more concrete use case and we'll be happy to see how it can either be solved using existing methods or implemented in a reasonable timeframe.

Thanks,
--Mike

T Toofoo

unread,
Mar 21, 2017, 11:18:39 AM3/21/17
to Firebase Google Group

HI.


Just a question to clarify:

Since it is possible to revoke a downloadURL from the Firebase console, would it be possible to have e new  client function that allow a User to revoke himself this  URL (of course only if he has write access on this file in the storage security rules) ? Did you plan to deliver such API one day ?



thanks
Reply all
Reply to author
Forward
0 new messages