限制访问Django中的私有文件下载

时间:2015-01-27 09:14:32

标签: python django django-file-upload

我的django应用中有多个FileFields,可以属于不同的用户。 我正在寻找一种限制对不是文件所有者的用户访问文件的好方法。

实现这一目标的最佳方法是什么?有什么想法吗?

4 个答案:

答案 0 :(得分:12)

不幸的是,@ Mikko的解决方案实际上无法在生产环境中工作,因为django 不是为提供文件而设计的。在生产环境中,您的应用程序/ django服务器(例如uwsgi,gunicorn,mod_wsgi等)需要由HTTP服务器(例如apache,nginx等)和 not 提供文件。

这就是为什么限制文件访问不是很容易:您需要一种方法让HTTP服务器询问应用程序服务器是否可以将文件提供给请求它的特定用户。如您所知,这需要修改您的应用程序您的http服务器。

上述问题的最佳解决方案是django-sendfile(https://github.com/johnsensible/django-sendfile),它使用X-SendFile机制来实现上述功能。我正在复制项目的描述:

  

这是用于将文件发送到Web客户端的特定于Web服务器的方法的包装器。当Django需要检查权限相关文件但不想提供文件本身的实际字节时,这很有用。即服务大文件不是Django的用途。

要了解有关senfile机制的更多信息,请阅读以下答案:Django - Understanding X-Sendfile

2018更新:请注意django-sendfile似乎不再维护;可能它仍然应该工作但是如果你想要一个具有类似功能的更现代的包,请看看https://github.com/edoburu/django-private-storage作为评论者@ surfer190建议。特别要确保实现“优化大文件传输”部分;你实际上需要这个所有传输不仅适用于大文件。

答案 1 :(得分:2)

如果您需要中等安全性,我的方法如下:

1)当用户上传文件时,为其生成难以猜测的路径。例如,您可以为/ static文件夹中的每个上载文件创建一个随机生成名称的文件夹。您可以使用以下示例代码完成此操作:

file_path = "/static/" + os.urandom(32).encode('hex') + "/" + file_name

通过这种方式,很难猜出其他用户的文件存储在哪里。

2)在数据库中将所有者链接到文件。示例模式可以是:

uploads(id, user_id, file_path)

3)使用模型中FileFields的属性以这种方式限制对文件的访问:

class YourModel(models.Model)
    _secret_file = models.FileField()

    def get_secret_file(self):
        # check in db if the user owns the file
        if True:
            return self._secret_file
        elif:
            return None # or something meaningful depanding on your app

    secret_file = property(get_secret_file)

答案 2 :(得分:1)

通常,您不会通过Apache,Nginx或您正在使用的任何Web服务器直接通过正常的静态文件路由私有文件。而是编写一个处理权限检查的自定义Django视图,然后将该文件作为流式下载返回。

  • 确保文件位于特殊的私人文件夹文件夹中,而不是通过Django的MEDIA_URLSTATIC_URL

  • 公开
  • 写一个

    的视图
    • 检查用户是否可以访问视图逻辑中的文件

    • 使用Python的open()

    • 打开文件
    • 返回HTTP响应,该响应将文件的句柄作为参数http.HttpResponse(_file, content_type="text/plain")

例如,请参阅download() here

答案 3 :(得分:1)

这最好由服务器处理,例如nginx secure link module(nginx必须使用"multipart/"编译)

文档中的示例:

--with-http_secure_link_module

该文件的访问方式如下:

location /some-url/ {
    secure_link $arg_md5,$arg_expires;
    secure_link_md5 "$secure_link_expires$uri$remote_addr some-secret";

    if ($secure_link = "") {
        return 403;
    }

    if ($secure_link = "0") {
        return 410;
    }

    if ($secure_link = "1") {
        // authorised...
    }
}

(这将是有时间限制的,并且绑定到该IP地址的用户)。

生成令牌以传递给用户将使用以下内容:

/some-url/some-file?md5=_e4Nc3iduzkWRm01TBBNYw&expires=2147483647