在数据库中存储上传的文件作为BLOB还是在有限制的文件夹中存储,哪种方式更好?

4
我正在项目中使用FileUpload。由于该网络应用程序需要与支付系统一起工作,因此将会面临高负载。我想知道,对于存储用户文件来说哪种方式更好呢?我的项目基于ASP.NET
我建议两种方案:
1. 将BLOB对象保存到数据库中/从数据库中加载 2. 将文件保存到/从文件夹中,并在表格中保存有关文件的信息以识别所有者,表格设计如下:BNF

<user_files> ::= ( <id ::= int, primary_key, auto_increment, indexed><user_id ::= int><file_guid ::= varchar(255)>) | nil

我更喜欢BLOB,但担心未来的高负载。因为从数据库中提取数据需要更多的CPU时间和内存分配,原因如下:
  • 我需要使用连接器,它将打开一个新套接字以连接到DB本地主机
  • 然后必须调用存储过程来获取BLOB对象
  • 在客户端,我必须从连接器的某些类中获取结果
  • 我必须反序列化它
  • 然后才能以未压缩和未损坏的状态向用户发送文件,以便用户以后可以在某个编辑器中打开它(文件通常是图像和MS Office文档)
我认为所有这些操作可能会减少服务器工作并需要更多时间,因此对于2000个在线用户,他们将非常快地交换文档,这种方式可能会很慢。
至于将文件存储在文件系统上,我只看到一个问题:
  • 正确保护文件的访问权限,因为不同的用户不能看到其他用户的文档,而且它们必须对其他用户隐藏。我担心,因为用户上传文件的文件夹对于IIS的Windows系统用户(IISUser...)是可见的,否则用户将无法上传任何东西,因此该文件夹将成为公共的。我唯一看到的解决方案是创建一个Windows服务,并使用IIS文件夹进行上传作为临时文件夹。 Windows服务将从中获取文件并将其放置到安全文件夹中,Web用户将无法看到它。
但是,也许我的想法有误,这就是为什么我向您寻求建议的原因,因为我希望使系统更加完美。
谢谢!
2个回答

3
如果您遇到这种情况,那么您已经违反了OWASP安全准则,因为您的文件存在不安全的直接对象引用。这意味着用户可以直接访问文件,因为您在IIS上打开了一个完整的子文件夹(如www.mysite.com/files/some_file.pdf),而且您的文件可能有名称。
您应该做的是:
  1. 在数据库中注册文件,其中包含唯一标识符;不包括数据,只包括名称和上传它的用户(可选包括权限或角色)。
  2. 将文件存储在磁盘上,其中文件名是数据库标识符。
  3. 不允许直接访问,而是编写一个特殊的HttpHandler,以获取文档的ID(就像在将文件存储在数据库中时所做的那样)。
采用这种方法,您可以实现以下目标:
  1. 文件有唯一的编号,可以防止它们在磁盘上出现命名冲突。
  2. HttpHandler 可以检查下载该文件的用户的数据库是否具有适当的权限。
  3. 由于使用了 ID,因此您不会受到规范表示攻击的影响,攻击者进行如下请求:www.mysite.com/file.ashx?file=..\web.config

因此,从安全角度来看,将文件存储在磁盘上而不是数据库中没有问题。


你的网站写入文件的文件夹应该位于 IIS 文件夹之外,并且运行你的网站的 IIS 用户应配置为具有该文件夹的读/写访问权限。 - Steven
这对我来说是相当奇怪的,因为ASP.NET网站无法保存到任何具有文件系统操作系统的文件夹中,因为在ASP.NET中通过FileUpload表单传输的所有文件都在CodeBehind中使用类似于System.IO.Path.Combine(Server.MapPath("uploads") 的方法,如果不使用Server命名空间,将会出现保存在服务器文件夹之外的异常,因此它将在任何情况下都保存在IIS文件夹中,因为ASP.NET项目托管在IIS上,并且不能看到比IIS更低级别的文件夹。 - Secret
如果将系统根文件夹的访问权限授予IIS-Users,似乎比在IIS文件夹中保存到子文件夹更麻烦。此外,我在ASP.NET中尝试将文件保存到C:\Program Files\project_name\user_uploads,即使已经允许了该文件夹的权限规则,也会抛出异常,其中包含有关拒绝访问IIS池之外的文件夹的信息...好的,我现在会再次测试,然后在此报告结果,也许我弄错了。 - Secret
我根本不使用确切的名称,而是为每个新文件生成 Guid.NewGuid(),我不想垃圾处理系统磁盘的根目录(这就是为什么)。 - Secret
顺便提一下,你可以看到这个主题,在这个主题中你可以看到我是如何保存文件的(我也在那个问题中回答了自己 :) http://stackoverflow.com/questions/15950638/dynamically-generated-fileuploads-cant-give-options/15991654#15991654 - Secret
显示剩余5条评论

2

将数据存储在数据库中,随着时间的推移,会更好地实现可扩展性。如果使用文件夹解决方案,并且有一天您需要或决定使用集群,则在整个服务器群中同步文件将是非常麻烦的。

尽管从数据库中获取内容可能更加耗费CPU资源,但它确实简化了许多事情(您的代码肯定更易于维护和移植),而且您始终可以指望托管和处理成本随着时间的推移而降低。

您还可以缓存内容以提高速度。无论哪种方式,我希望这些文件上传后不要经常更改。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接