DEV Community

[Comment from a deleted post]
Collapse
 
r002 profile image
Robert Lin

Hi David-- thank you so much for sharing your findings! I started digging into Firebase storage today and am still wrapping my head around how it all works. Even though it has security rules, it actually works differently than Firestore (which I'm familiar with) so at first it was a bit of a head-scratcher.

Quick question though, just to confirm something: Did you ever find out a way to programmatically regenerate the "access token" every single time a Firebase storage file is accessed? I read through the SO links you posted and saw Doug's answer, but the approach, if I'm understanding it correctly, doesn't work for my use case. Even if the "download url" is 99.99999% "unguessable," it is simply NOT acceptable (in my use case) for a long-lived public url to be floating around on the interwebs anywhere.

Thus-- I'm in a situation now where I'd like to either regenerate the access token every single time the file is accessed or proxy a byte stream to the end user (after they've passed some firestore checks). Did you end up adopting a similar approach for your DeckDeckGo (cool name, btw! ๐Ÿ‘) app?

PS. FYI, these two articles also helped me:
techotopia.com/index.php?title=A_G...

sentinelstand.com/article/guide-to...

I know about "signed urls" but there seems to be some caveats so I haven't dug into those yet. Or did you end up using those?

Thanks for helping!! ๐Ÿ™๐Ÿ™๐Ÿ™

Collapse
 
daviddalbusco profile image
David Dal Busco • Edited

Hi Robert, thank you for your feedback and interesting questions!

I did not find another way to programmatically generate the "access token" and, accepted to go on with the 99,9999999999999% "unguessable download urls" rules / limitation.

If I would have to implement a different path, I would probably either try out one of the methods displayed in the guide to Firebase Storage download URLs and tokens you linked above or, try out again the methods I had developed before I reverted my changes (basically encapsulating all images in components and processing the fetching "manually" with custom tokens) but, that's quite some overhead and not sure it would be fully bullet proof neither, that would be some work.

That being said, my article is one year old. Don't know if there were improvements meanwhile? I had quickly a look to the typescript definition of the storage but, did not noticed such new options though.

Regarding rules, one of the few things I added, which is not described here, is limiting the files upload size.

match /{userId}/assets/images/{allPaths=**} {
      allow write: if request.auth.uid == userId && 
               request.resource.size <= 10 * 1024 * 1024;
      allow read: if request.auth.uid == userId;
    }
Enter fullscreen mode Exit fullscreen mode

If you ever find a solution or improve the setup, please let me know!

Collapse
 
r002 profile image
Robert Lin

Hi David-- I wanted to just follow up on this thread quickly. After spending a few hours poking around today, I think I finally figured it out-- a way to deliver secure assets (without revealing the asset's underlying permalink) to authorized users.

I wrote up my findings here, if you want to take a look. I achieved it without using any of Firebase's built-in signed-urls or download-urls generators though because from my reading, all those approaches always revealed the assets underlying permalink which I didn't want.

Again, I'm new to Firebase so I'm not positive my approach is 100% full-proof, but I monitored the network tab in Chrome's dev tools console and didn't see any permalinks being unwittingly revealed. So I guess that's at least a start in the right direction. Please let me know if you have any questions or are curious about anything. Firebase is seriously amazing though! It's so good! ๐ŸŽ‰๐Ÿฅณ

 
daviddalbusco profile image
David Dal Busco

Thanks for the follow up Robert ๐Ÿ˜ƒ.

It looks like the same approach as the one I described in my post ("Fetch: Access Image Securely With OAuth2") but, instead of doing the work on the client side, you defer it to a Function. That's a creative and interesting approach ๐Ÿ‘.

Nevertheless, regarding the downloadUrl, I am not sure it is "solved". Last time I had a deep look at the question, I figured out that such url are automatically generated by Firebase on each upload, regardless if such a link is called from the client side or not. It might have been a bug but, as long as I remember, it was so. Therefore if you really do not want such link, you would "still" have explicitly ask Firebase to remove it which, as far as I understand, is only possible with GCP but again, I might be wrong and no such link might be automatically generated. It is probably worth a try and look.

Again thanks for the follow-up, really cool!

 
r002 profile image
Robert Lin

Hi David!

So, two quick notes:

First-- yes, regarding the downloadUrl-- I believe you are correct: The moment any file is uploaded to FB Storage, the Google Team, in their infinite wisdom, appears to have decided to by default create a mandatory public url that links to the storage asset. There are ways to bypass this if you're using GCP but with FB, it seems like we don't have a choice. Todd, Frank, David, Doug, et al all strike me as genius-level people so I'm sure there's a legit design decision for this impl. But I have no idea what it is. To me, it just seems like a potential security disaster waiting to happenโ€ฆ automatically creating a "public url backdoor" to any FB storage asset seemsโ€ฆ not good? ๐Ÿค”

(Again, I'm new to FB though so I feel like I honestly must be missing something or am incompletely understanding somewhere. Please lmk if so!)

Second-- so my approach is similar to the one you describe but also different in one significant way (I think). Just so I understand your solution though: In your example, where you specified the endpoint of
https://firebasestorage.googleapis.com/.../photo.jpg
and then manually send in the header:
'Authorization': Bearer ${firebase_user_auth_token}

What is ${firebase_user_auth_token} in this example? Are you getting it from here?

 
daviddalbusco profile image
David Dal Busco

I wish I would still be able to have a look to my source code to answer your question regarding firebase_user_auth_token but, as I ditched my concept and went with the dowloaUrl, gonna be hard to find and remember. Honestly don't remember spontaneously, really sorry. Not sure if it is one I fetch with the Firebase SDK or one I define, get and add "manually" as metadata to the assets.

Thanks again for all the feedbacks, really interesting inputs and ideas!

 
r002 profile image
Robert Lin

No worries! ๐Ÿ‘ Again, thanks for sharing all of this info on Firebase Storage-- it's super-helpful! Gracias!! ๐Ÿ™

Collapse
 
r002 profile image
Robert Lin

Got it! Thanks, David, for your quick reply! ๐Ÿ™

Okay, I'm going to investigate more today; will keep this thread posted with my findings.

I'm new to Firebase and have been loving it so far. But the way the Google team has designed storage (if I'm understanding it correctly) is honestly baffling to me. Generally, to my knowledge at least, a good platform will provide three ways to access storage:

  1. Public short link (like youtu.be/*** or bit.ly/** links). Nice, short, shareable.

  2. Super-long "unguessable" link. Public but only if shared ad-hoc. So effectively, private (kinda).

  3. Actually-secure. Every single access of the protected asset requires an authentication/authorization check.

The fact that Firebase (again, if I'm understanding it correctly) only offers "security through obfuscation" (option 2) as its most easy-to-implement approach is bizarre to me and honestly not very secure (IMHO). I'll dig into it more today though; thanks! ๐Ÿ‘