下载文件保存到磁盘时的浏览器事件

IT技术 javascript browser download save dom-events
2021-02-06 21:03:56

我有敏感文件要下载给用户,每个用户只能下载一次给定的文件。如果下载失败,我想允许重新下载,但不允许重新下载。

仅依靠在服务器上记录/处理文件下载请求不够的 - 我需要确定性地知道文件何时完成并在客户端就位,因为我的许多用户在连接频繁中断的环境中工作。

最直接的方法是让浏览器从 Save As... 对话框中暴露一个“文件保存”事件,该事件可以连接到下载页面上的 JavaScript 函数(可以回发到服务器)。但是,直觉表明,如果浏览器公开此功能,则可能存在安全漏洞,因为它在沙箱之外有些偷偷摸摸。我不确定这是否可能。

在这方面发现 其他 几个问题 ,但没有特别针对这个问题。

有任何想法吗?

编辑:我不应该在原始问题中使用“安全”这个词,抱歉触发了红鲱鱼。

编辑 2:我的“安全”措辞误导人们进入离题的技术安全问题,但你们两人证实了我的怀疑“不,浏览器不支持”。我正在用答案标记第一个评论者,因为他的第一句话就是我想要的。谢谢大家。

3个回答

这是一个很好的解决方案:

http://gruffcode.com/2010/10/28/detecting-the-file-download-dialog-in-the-browser/

它基本上是通过在下载文件的响应头中设置一个 cookie 来工作的,所以 javascript 可以定期检查这个 cookie 的存在......

JavaScript 中没有这样的浏览器事件,即使有,您也不能相信用户的浏览器会为您提供安全性。

最好使用 GUID 为每次下载生成唯一的 URL。然后你可以例如:

  • 让 URL 仅在特定时间段内有效
  • 仅允许从与唯一 URL 关联的特定 IP 地址进行传输
  • 让您的服务器端代码检测唯一 URL 的内容何时已完全传输,然后使该 URL 无效。

让我澄清最后一个要点。假设你使用的是Java -你会in.read(buffer)out.write(buffer)一个循环,直到EOF。如果客户端断开连接,您将收到一个IOException过程,out.write()并且能够从中断的下载中分辨出下载成功。在其他平台上,我确信有办法判断连接是否丢失。

编辑:您实际上可以使用您链接到的问题之一的已接受答案中概述的技巧来触发浏览器事件然而,这不是限制下载数量的可靠解决方案。

我肯定会选择第 3 项,服务器当然可以知道连接是否已丢失。
2021-03-24 21:03:56
感谢您的回复。是的,我第一次理解了你的第 3 个项目,但它不符合要求。:) 在 ASP.NET 中,等效的是 Response.WriteFile() 和它的朋友,甚至还有一个 Response.IsClientConnected 属性要检查。不幸的是,由于 TCP 的工作方式,这两种方式在服务器看来都是成功/连接的,而字节却没有成功到达客户端。您会惊讶于这种情况在高度不可靠的网络环境中发生的频率如此之高。因此需要客户端检测。
2021-03-25 21:03:56
@Adrian - 因为它不是那种安全性。它更多地是关于法律术语与客户体验的对抗,而不是技术,我正试图找到一种方法,以“尽力而为”的方式使用技术来适应法律术语。
2021-04-02 21:03:56
当然,访问控制将由您描述的机制(和其他机制)提供。不过,这是一个单独的问题。我也完全同意面对蓄意攻击时信任客户端代码的不可靠性;幸运的是,在我的环境中,我可以接受这个问题。我的问题是保证一次成功下载(客户端上的字节数),而不依赖于服务器做出决定(您的第三个项目符号)。问题在于服务器可以相信它已经传输了文件,而所有字节都没有成功到达客户端。
2021-04-07 21:03:56
如果你可以接受一个只有在不被故意攻击时才起作用的“安全”系统,为什么不相信用户会按照他们的指示去做呢?那没有任何意义...
2021-04-09 21:03:56

为什么文件可以“恰好一次”下载很重要?一旦文件被下载,它就可以被复制,那么让同一个用户多次下载文件真的存在安全问题吗?

如果没有,你能不能做这样的事情:

  1. 生成一个唯一的 URL 来下载给定的文件。(如有必要,使用 GUID 进行混淆)
  2. 将该 URL 与用户信息(浏览器类型、IP 地址等)和时间窗口相关联。只允许从该用户和窗口期间下载。
  3. 该窗口应该足够长,以便用户注意到传输失败并重试一两次,但不再重试。

最终结果是:

  1. 您可以合理地确定该文件仅由预期收件人下载。
  2. 您可以确定收件人只能在很短的时间内下载文件。
  3. 同一个用户可以多次下载文件,但谁在乎呢?这与制作第一个文件的本地副本没有什么不同。

如果您真的很担心,请记录每个下载请求并为多次下载的文件运行计划报告。如果有任何事情看起来可疑,您可以检查安全日志,与用户交谈等。

如果可能的话,鉴于我们用户的复杂程度较低,并且能够对更复杂的攻击者可能造成的损害进行时间限制,那么它可能“足够”可靠地满足合同要求(即它会如果在技术上不是密封的,则在法律上是可以辩护的)。但根据迄今为止的答复,我确认我怀疑这是不可能的。感谢您抽出宝贵的时间!
2021-03-14 21:03:56
这是一个外部合同要求:给定的用户可以下载文件一次。问题在于确定该事件何时发生。当然,关于下载文件后复制的便利性,您是对的。在这里你不能太严格地应用逻辑,这不是纯粹的技术问题。:) 你对 userinfo/timestamp 的建议已经是设计的一部分,还有一些其他的好东西。
2021-03-21 21:03:56
@大卫:无赖。在没有任何内置功能(我认为不存在)的情况下,您依靠客户端来告诉您下载何时完成,而这本质上是不可靠的;客户端设置一个代理来阻止发送确认并不会太难。您是否考虑过设置一个数据包嗅探器或网络监控工具来告诉您文件的所有数据包是否已发送出去?仍然不意味着它们已成功接收,但它比“嘿浏览器,完成后通知我”更可靠:)
2021-03-30 21:03:56
也许您可以从客户端获取 ip 和 datetimestamp 并将其与 ftp 日志文件进行比较。
2021-04-11 21:03:56