- From: Jonas Sicking <jonas@sicking.cc>
- Date: Fri, 15 Jul 2011 16:00:03 -0700
2011/7/15 Darin Fisher <darin at chromium.org>: > On Fri, Jul 15, 2011 at 1:09 PM, Jonas Sicking <jonas at sicking.cc> wrote: >> >> 2011/7/15 Ian Fette (????????) <ifette at google.com>: >> > 2011/7/15 Jonas Sicking <jonas at sicking.cc> >> > >> >> 2011/7/14 Ian Fette (????????) <ifette at google.com>: >> >> > Many websites wish to offer a file for download, even though it could >> >> > potentially be viewed inline (take images, PDFs, or word documents as >> >> > an >> >> > example). Traditionally the only way to achieve this is to set a >> >> > content-disposition header. *However, sometimes it is not possible >> >> > for >> >> the >> >> > page author to have control over the response headers sent by the >> >> > server.*(A related example is offline apps, which may wish to provide >> >> > the user with >> >> > a way to "download" a file stored locally using the filesystem API >> >> > but >> >> again >> >> > can't set any headers.) It would be nice to provide the page author >> >> > with >> >> a >> >> > client side mechanism to trigger a download. >> >> > >> >> > After mulling this over with some application developers who are >> >> > trying >> >> to >> >> > use this functionality, it seems like adding a "rel" attribute to the >> >> > <a> >> >> > tag would be a straightforward, minimally invasive way to address >> >> > this >> >> use >> >> > case. <a rel=attachment href=blah.pdf> would indicate that the >> >> > browser >> >> > should treat this link as if the response came with a >> >> content-disposition: >> >> > attachment header, and offer to download/save the file for the user. >> >> >> >> We've discussed a different solution to the same problem at mozilla. >> >> The solution we discussed was allowing FileSaver to in addition to >> >> taking a blob argument, allow it to take a url argument. >> >> >> >> One concern which was brought up was the ability to cause the user to >> >> download a file from a third party site. I.e. this would allow >> >> evil.com to trick the user into downloading an email from the users >> >> webmail, or download a page from their bank which contains all their >> >> banking information. It might be easier to then trick the user into >> >> re-uploading the saved file to evil.com since from a user's >> >> perspective, it looked like the file came from evil.com >> >> >> >> Another possible attack goes something like: >> >> 1. evil.com tricks the user into downloading sensitive data from >> >> bank.com >> >> 2. evil.com then asks the user to download a html from evil.com and >> >> open the newly downloaded file >> >> 3. the html file contains script which reads the contents from the >> >> file downloaded from bank.com and sends it back to evil.com >> >> >> >> Step 1 and 2 require the user to answer "yes" to a dialog displayed by >> >> the browser. However it's well known that users very often hit >> >> whichever button they suspect will make the dialog go away, rather >> >> than actually read the contents of the dialog. >> >> Step 3 again requires the user to answer "yes" to a dialog displayed >> >> by the browser in at least some browsers. Same caveat applies though. >> >> >> >> One very simple remedy to this would be to require CORS opt-in for >> >> cross-site downloads. For same-site downloads no special opt-in would >> >> be required of course. >> >> >> >> It's also possible that it would be ok to do this without any opt-ins >> >> since there are a good number of actions that the user has to take in >> >> all these scenarios. Definitely something that I'd be ok with >> >> discussing with our security team. >> >> >> >> Tentatively I would feel safer with the CORS option though. And again, >> >> for same-site downloads this isn't a problem at all, but I suspect >> >> that in many cases the file to be downloaded is hosted on a separate >> >> server. >> >> >> >> Oh, and I don't have strong opinions at this time on if rel=attachment >> >> or FileSaver or both should be the way to trigger this functionality. >> >> >> >> / Jonas >> >> >> > >> > I agree FileSaver is useful and has its place, but I don't think it >> > negates >> > the need for something like rel=attachment or download=filename. For >> > one, >> > FileSaver currently operates on blobs and as you mention would have to >> > be >> > modified to handle URLs or streams more generally. Second, it would >> > force >> > developers to use javascript links and/or set up click listeners and so >> > forth, which could be annoying for users (losing the ability to copy the >> > URL >> > etc). >> >> As stated, I don't have a strong preference here. I suspect ultimately >> we'll end up wanting both a markup based and an API based solution >> here. >> >> > I guess the interesting question is "If the response would not have >> > otherwise triggered a download, and the request is cross-origin, should >> > that >> > require CORS" and personally I would say no, this is still a remote >> > enough >> > concern that I would not worry about it. >> >> Indeed, that is the interesting question. >> >> I know that I would personally feel a lot more comfortable if the site >> opted in to allowing downloads of the resource in question. But it's >> quite possible that I'm overly paranoid. >> >> Though one thing to keep in mind is sites that explicitly state that a >> resource should *not* reach the users disk. This is today often done >> using "Cache-Control: no-store". Seems scary to allow such content to >> be saved based on a cross-site request. >> >> / Jonas > > > This security concern is very interesting. I had not considered it before. > Putting that aside for a moment, I'm glad to hear that you also support > there being some declarative method of triggering a download. Which of > the proposals are you leaning toward? > Personally, I'm most fond of the @download=filename method. Reason: > 1) Unlike rel=something, @download is feature detectable at runtime via > ("download" in document.createElement("a")). > 2) Unlike rel=something, @download provides a way to specify the name > of the file to save. This makes the feature useful with data: URLs and > blob: > URLs (that are not backed by a single file). This is valuable to me because > I can imagine wanting to save the contents of a <canvas>, and that probably > involves saving the data URL that you get from toDataURL(). > 3) The target=_download idea is interesting, but I'm not sure we can safely > introduce new target values, and this also suffers from not providing a way > to > specify the downloaded filename. > 4) The idea of using both a rel=something and an attribute to specify the > file > name could work too, but it seems a bit overly verbose. I'm not sure I see > enough benefit from this. The idea of providing a name for <img> tags that > might be downloaded manually by the user is interesting, but it feels like a > far less interesting problem to solve. If our solution solves this too, > then great, > but I wouldn't necessarily make it a requirement to solve this problem too. > Anyways, what do you think? I'd really like to reach some consensus on what > the declarative method should look like. I agree! I like the @download attribute the best so far for basically the same reasons you enumerate. It's also a very memorable name. It definitely is an interesting usecase that Glenn brought up about being able to specify a save-as name without otherwise modifying the behavior of a reference. However that seems like a much more rare usecase and so not the one we should optimize for. Another UI feature that this all would allow is the ability to drag-out-to-save. I.e. if the user drags a <a href="..." download="..."> to the desktop, the browser can treat that as a saving action. > Whatever security restrictions we come up with will need to apply to > FileSaver > too assuming FileSaver ends up taking an URL (and a filename!). Absolutely! I think that the model Ian summarized in his last email is a good one. Same-origin is always allowed, cross-origin is only allowed if there is CORS or content-disposition: attachment. / Jonas
Received on Friday, 15 July 2011 16:00:03 UTC