[whatwg] a rel=attachment

Jonas Sicking jonas at sicking.cc
Fri Jul 15 16:00:03 PDT 2011


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


More information about the whatwg mailing list