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?
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.
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! ๐๐ฅณ
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.
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?
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!
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:
Public short link (like youtu.be/*** or bit.ly/** links). Nice, short, shareable.
Super-long "unguessable" link. Public but only if shared ad-hoc. So effectively, private (kinda).
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! ๐
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
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!! ๐๐๐
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.
If you ever find a solution or improve the setup, please let me know!
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
ordownload-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! ๐๐ฅณ
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!
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?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!
No worries! ๐ Again, thanks for sharing all of this info on Firebase Storage-- it's super-helpful! Gracias!! ๐
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:
Public short link (like youtu.be/*** or bit.ly/** links). Nice, short, shareable.
Super-long "unguessable" link. Public but only if shared ad-hoc. So effectively, private (kinda).
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! ๐