views:

193

answers:

2

I have sensitive files to download to users, and each user is permitted to download a given file exactly once. If the download fails, I want to permit the re-download, but not otherwise.

It's not sufficient to rely on logging/processing the file download request at the server - I need to know deterministically when the file is complete and in place at the client, since many of my users work in an environment with frequent connectivity drops.

The most straightforward way for this to work would be if the browser exposed a "file saved" event from the Save As... dialog that could be wired to a JavaScript function on the download page (which could post back to the server). But, intuition suggests there might be security holes if browsers exposed this functionality, as it sneaks somewhat outside the sandbox. I'm not sure this is even possible.

I found several other questions in this area, but nothing about this problem specifically.

Any ideas?

Edit: I should not have used the word "security" in the original question, sorry for triggering the red herrings.

Edit 2: My "security" phrasing misled folks into offtopic technical security issues, but both of you confirmed my suspicion that "no, there's no browser support for that." I'm marking the first commenter with the answer since his first sentence had what I was looking for. Thanks all.

+2  A: 

There's no such browser event in JavaScript and even if there was you can not trust the user's browser to provide security for you.

You're better off using a GUID to generate a unique URL for each download. You can then for example:

  • let the URL be valid only for a specific time period
  • allow transfers only from a specific IP address associated with the unique URL
  • let your server-side code detect when the content for a unique URL has been fully transferred and then invalidate the URL.

Let me clarify the last bullet. Say you're using Java - you will in.read(buffer) and out.write(buffer) in a loop until EOF. If the client disconnects you will receive an IOException during out.write() and will be able to tell a successful download from an interrupted one. On other platforms, I'm sure there are ways to tell whether the connection was lost or not.

EDIT: You could actually fire a browser event using the trick outlined in the accepted answer of one of the questions you linked to. That would however not be a reliable solution to limit the number of downloads.

Martin
Certainly, access control will be provided by the mechanisms you describe (and others). That's a separate question, though. I also completely agree about the unreliability of trusting client-side code in the face of deliberate attack; fortunately, in my environment I can accept that problem.My question is about guaranteeing one successful download (bytes-on-the-client), without relying on the server to make the decision (your 3rd bullet). The problem there is that the server can believe it has transferred the file, without all the bytes successfully arriving at the client.
David Pope
I would definitely go for the 3rd bullet, it is certainly possible for the server to know whether the connection has been lost or not.
Martin
If you can accept a "security" system that works only when not deliberately attacked, why not just trust the users to do as they are told? That doesn't make any sense...
Adrian Schmidt
Thanks for your replies. Yes, I understood your 3rd bullet the first time but it didn't meet the requirements. :) In ASP.NET, the equivalent is Response.WriteFile() and its friends, and there's even a Response.IsClientConnected property to check afterward. Unfortunately, due to the way TCP works, both of these can appear to the server to be successful/connected, without the bytes having successfully arrived at the client. You'd be surprised how frequently this happens in a highly unreliable network environment. Hence the desire for client-side detection.
David Pope
@Adrian - Because it's not that kind of security. It's more about legalese-working-against-customer-experience than technology, and I'm trying to find a way to use technology to accommodate the legalese in a "best-effort" kind of way.
David Pope
A: 

Why is it important that the file can be downloaded "exactly once"? Once the file is downloaded it could be copied, so is there really a security issue with letting the same user download the file more than once?

If not, could you do something like this:

  1. Generate a unique URL to download a given file. (Use a GUID to obsfucate if necessary)
  2. Associate that URL with USER INFO (browser type, IP address, etc) AND A TIME WINDOW. Only allow downloads from that user and during the window.
  3. The window should be long enough for the user to notice the transfer failed and to re-try once or twice, but no longer.

The end result is:

  1. You can be reasonably sure the file is only being downloaded by the intended recipient.
  2. You can be sure that recipient can only download the file during a short window.
  3. The same user could download the file more than once, but who cares? It's no different than making a local copy of the first file.

If you're really worried about it, log each download request and run a scheduled report for files that were downloaded more than once. If anything looks fishy you can then examine security logs, talk to the user, etc.

Seth Petry-Johnson
It's an external contractual requirement: A given user may download the file once. The problem is determining when that event has happened. You're right, of course, about the ease of copying once a file is downloaded. You can't apply logic too stringently here, it's not purely a technical issue. :) Your suggestion about userinfo/timestamp was already part of the design, along with some other goodies.
David Pope
@David: bummer. In the absence of any built-in feature (which I don't think exists) you are relying on the client to tell you when the download is finished, and that's inherently unreliable; it wouldn't be too hard for a client to set up a proxy that blocks that confirmation from being sent out. Have you thought about setting up a packet sniffer or network monitoring tool that can tell you if all of the file's packets have been sent out? Still doesn't mean they were successfully _received_, but its more reliable than "hey browser, let me know when you're done" :)
Seth Petry-Johnson
If it were possible, given the low sophistication level of our users and the ability to time-limit the damage that could be done by a more-sophisticated attacker, it would likely be reliable "enough" to satisfy the contractual requirement (i.e. it would be legally defensible, if not technically airtight). But based on the replies so far, I'm confirming my suspicion that it isn't possible. Thanks for taking the time!
David Pope
may be you can get the ip and datetimestamp from client and compare it with ftp log files.
drorhan