Attachment downloads in browsers

59 views
Skip to first unread message

D David

unread,
Jun 14, 2016, 3:41:42 AM6/14/16
to JMAP
Hi JMAPers,

At Linagora we're making good progress on our JMAP implementation, currently completing the "attachments" part.
I'd like to raise a concern regarding the specification about attachments download (important part in bold):

downloadUrl: String The URL endpoint to use when downloading files, in RFC6570 URI Template (level 1) format. The URL MUST contain a variable called blobId. The URL SHOULD contain a variable called name. The client may use this template in combination with a blobId to download any binary data (files) referenced by other objects. Since a blob is not associated with a particular name, the template SHOULD allow a name to be substituted in as well; the server will return this as the filename if it sets a Content-Disposition header. To download the data the client MUST make an authenticated GET request (see below for how to authenticate requests) to the expanded URL, and then follow any redirects.

While this is perfectly fine, it is really not friendly to a client implementation running in a browser (as we currently do) because you can't change sent headers when using native browser tools (a link, a call to window.open, etc.) for file downloads. Workarounds include crappy solutions, amongst them:
  • Switch to a cookie-based authentication (booooh !)
  • Proxy the download request through any backend capable of setting request headers
  • Download the file using an Ajax request then asks the user to download a manually-created Blob (really not scalable)

I have a proposal to enrich the spec on this part to allow easy file downloads inside a browser (keeping the authentication on the download endpoint) but I'd like to hear from other implementers about that. How do you do it when running inside a browser?

My proposal would be to amend the spec to propose a signing mechanism for attachment download requests, very similar to what Amazon is doing on the AWS API. The process is as follows:
  • The client makes an authenticated POST to the interpolated downloadUrl (with all available variables substituted).
  • The server replies with a crafted "token". This token has a very short expiration time, and expires as soon as it is used.
  • The client downloads the file using an unauthenticated GET request, passing the token in the query String.

WDYT?

Regards,
David

Neil Jenkins

unread,
Jun 15, 2016, 2:13:52 AM6/15/16
to JMAP Mailing List
Hi David,
 
I have a proposal to enrich the spec on this part to allow easy file downloads inside a browser (keeping the authentication on the download endpoint) but I'd like to hear from other implementers about that. How do you do it when running inside a browser?
 
Well, firstly we make a slight change when running JMAP in the browser: we set a cookie that must be sent back by the browser in addition to the normal Authorization header (note, this doesn't change anything about the JMAP auth protocol as far as the code running in the browser is concerned; it's automatically set and checked by the server). This is primarily an extra layer of security: should there be a successful XSS attack against our webmail, it would only be able to perform actions on the user's account while the tab is still open – as the cookie is HTTP-only, it can't be exfiltrated by JavaScript.
 
Downloads are a further special case – we open all 3rd party content on a different domain to take advantage of the browser's cross-domain restrictions so malicious content has no access to credentials. By design, this doesn't get the normal session cookie, so we do a complicated dance of redirects to set a different cookie on this domain and make sure no credentials are leaked in the Referer header. I won't bother to explain the exact details, because your proposal below is much better!
 
My proposal would be to amend the spec to propose a signing mechanism for attachment download requests, very similar to what Amazon is doing on the AWS API. The process is as follows:
  • The client makes an authenticated POST to the interpolated downloadUrl (with all available variables substituted).
  • The server replies with a crafted "token". This token has a very short expiration time, and expires as soon as it is used.
  • The client downloads the file using an unauthenticated GET request, passing the token in the query String.
 
I like this. It's simple but secure (depending on how the token is generated of course), and easy to use across domains. Do you want to make a pull request on the spec?
 
Cheers,
 
Neil.

D David

unread,
Jun 15, 2016, 1:31:35 PM6/15/16
to JMAP
Hey Neil, sure I'll do the PR ASAP.

David

D David

unread,
Jun 17, 2016, 5:55:30 AM6/17/16
to JMAP
Hey guys, PR is there https://github.com/jmapio/jmap/pull/48/files

Cheers,
David
Reply all
Reply to author
Forward
0 new messages