-
Notifications
You must be signed in to change notification settings - Fork 928
FR: Alternative to getDownloadURL that doesn't expose a public download URL #76
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
We've been considering something like this for a while. The reason we decided to only expose a downloadURL on web is because of its versatility. If we wanted to give you a way to download the file checked by security rules, the best we could do would probably be to give you an XMLHttpRequest you could use to download the object yourself. The problem with this is that if you're using an XHR the downloaded data ends up in memory, which means if it's a large file (say, more than a few gigabytes) it's difficult to do anything reasonable with the XHR. On the other hand, with a download URL, many things are simpler (you can embed it directly in an img tag) and you can give the user the option to download the file (an Of course, it's also easier for anybody to automate abusive behavior if they have a download URL (as you pointed out). At the same time, for a sufficiently dedicated malicious user there isn't a big difference between exposing the download URL vs not exposing it (any user capable of downloading the file via security rules can get a download URL and do anything they want with it). As a result, we don't consider this a high-priority change. |
Could you clarify (apologies if these questions are better addressed elsewhere):
|
|
Thanks @sphippen, regarding (2) I don't quite understand: if I authenticate with FB and ask for
|
Sorry, I misunderstood what you meant by So, if you log a Google user into your app with Firebase Auth and request the
Exactly correct. To summarize, the Firebase Auth JWT lets you access buckets associated with the project in which they were created through Firebase Storage. The Storage security rules are applied to these requests. (third-party auth) If you log a Google user into your app, they'll click through a page granting you the permissions you request, and the OAuth accessToken will give you those permissions. You can use that token to make requests to GCS' normal API, but only to access resources the user already has access to through Cloud IAM or GCS' legacy ACL system. (first-party auth) |
Thanks @sphippen! I've tested this approach and it works as you described. Hopefully it will help others as an alternative to That being said, requesting a |
I have a really basic question. |
In general, we return the same download URL. It is however possible to revoke an old URL in the Console, in which the next invocation will return a different URL. |
Hello, |
@tborja is right.. this is a major problem and I'm very very concerned that it hasn't been addressed yet. Once this is handed out, there are NO security rules applied for reading that document. This isn't really highlighted anywhere in the SDK docs and it's really really easy for a developer to shoot themselves in the foot here. Specifically, I just did. I had assumed that getDownloadUrl would apply the storage security rules but that's not the case. I'm going to have to spend 1-2 weeks building an alternative. Why can't there just be a proxy in between that evaluates the rules on every HTTP request and passes the rest on to cloud storage? That's literally what I'm going to be doing next but Firebase should be doing this for me... Maybe change this API call to getInsecureDownloadURL or getPublicDownloadURL or at least highlight in the API docs that there are NO security rules applied to this URL once created. |
Is there a way to revoke them via API and not manually? I'm working on a feature for public sharing of documents and this way I could at least revoke the URL and generate a new one. |
As an alternative, you can generate a signed URL with an expiration time using admin SDK inside a cloud function. |
I saw that but this doesn't really rectify the problem. Once the timed URL is issued there's no way to revoke it... This is back to the same issue. I need to hand out the URLs up to the moment the user revokes access. This is why the Firebase rules would be ideal for this situation. |
As a way around this problem, one could request a signed URL with a very short expiration time, upon user request. This way, the first time they request the URL through a cloud function, they obtain a link, but it will expire within seconds (or minutes maybe, I cannot recall what the lower limit is). Would that work for you? |
@dinvlad What we could use is a method on the client SDK that has a fixed expiry on the download URL where the actual expiry term isn't defined in the user-agent. That would prevent people from just flat-out hacking the expiry value seeded into an API like the Forgive the inelegance, but something like The alternative currently is just to create an HTTPs Function that generates a short-term URL in the AuthN context for the Firebase user. This is a bummer, since calling |
IMO even having it as an option on the client would be good. For now, we just have to resort to |
I'm facing the same problem. My web app's users upload their private data to |
Hi @garyo, The only things is that this Firebase Storage Gotchas 😅 documents helped me. I hope it can help you too! |
Hi @schmidt-sebastian question that's related to this. We've received requests to add Has adding |
Adding It would also allow us to use this Firebase functionality in Cloud Functions without storing tokens manually as metadata and bypassing It doesn't solve the issue of download URLs being persistent and having no inherent security checks. But, creating a persistent, obscure URL that has no inherent security check ( I agree that having a "short-lived" option would be ideal, either as a new method or as an argument to |
@frankyn We currently bundle the
|
@schmidt-sebastian @frankyn Downloading files inside an applicationI think the request in the original post was overlooked a bit in the discussion here.
I understand the reasoning for exposing Consider this implementation: This could definitely be implemented with Of course you could argue that they could also just download the file and share it. I think the point here though is to limit any accidental exposure that could occur. For what it's worth, creating an authenticated XMLHttpRequest to firebasestorage.googleapis is really simple (requires a JWT token passed through an
|
@schmidt-sebastian @avolkovi |
@tonyjhuang can you take a look? |
@tonyjhuang @schmidt-sebastian Thanks for your help. |
Hi @nVitius we have an idea on how to support temporary download URLs but we probably won't have resources to pursue it this quarter. I'll keep this thread updated as our timeline changes. Related to this feature would be to change permanent download token generation to be an opt-in process so users that fetch the object with the temporary URL won't be able to scrape the permanent token from the metadata but that will have to be a separate effort as it would require changes across our SDKs. |
Hi Everyone !
Thanks .. Sorry for a lot of content and text :) |
@kevinmmansour The way I've done this before is to set the access rules to the avatars as public. Then you don't need to use the downloadURL. If you must maintain the permissions, then you can download the image using XHR and dynamically set the I agree though, that it would be great to see the addition of downloadURLs that don't use query parameters for the token. For what it's worth, you can also generate your own UUID and set it as the filename and use public permissions. This provides essentially the same security that the |
@tonyjhuang I appreciate your reply. I know this was a while ago, but I wanted to add a couple comments: I know that the Firebase team supports a lot of projects and has their own internal roadmap. I understand that some things take priority over others. That said, the developers on here asking for information about feature development and offering ideas on how they would like things to be solved are not just your users but also your paying customers. I personally love working with Firebase and I recommend it as a solution to most of my clients and colleagues. But It can be frustrating not having much (often none at all) insight into what the team is working on and if certain issues/features are at least being considered. I imagine that this is most likely not something that is up to you. I hope at least that someone sees this and can raise the concerns with the internal team and there can be more discussion around this. |
@nVitius Really appreciate your reply. I just solved it by Uploading the photo to Firebase Storage then get download url then store it inside Firebase Auth (photoURL) to solve that but it really worked after finding answer on google. Thanks again for your reply as you give some time for my comment to read it . I hope Firebase Team create more simplest method to do that with more features which will help a lot of developers to finish their project. |
Client-Side, Security-Rule-Compliant Firebase Storage Fetch of IMagesIt is possible, and relatively straight-forward, to download a Firebase Storage object to client while fully respecting Security Rules - but, as noticed above, it is NOT possible directly from an
You can use the following to generate the URL to a known storage object:
|
[REQUIRED] Describe your environment
[REQUIRED] Describe the problem
Currently, the only way to get an image is to call
getDownloadUrl
. The download URL is unguessable but not affected by security rules, which means that once someone has the download URL, they could theoretically use a bot to create a huge number of downloads and run up a big Cloud Storage bill or hit the project quota.The Android SDK provides
getFile
, which downloads the file directly to the device. Each download involves a security rules check (source).Request
Provide a function like
getFile
that checks security rules every time.Alternatively, perhaps a function that returns a signed URL (for example,
getSignedUrl(expireTime)
) could accomplish a similar goal.The text was updated successfully, but these errors were encountered: