我正在构建一个系统,允许用户生成文档然后下载它们。这些文档是 PDF(对于这个问题来说这并不重要),当它们生成时,我将它们存储在 Web 服务器运行的本地文件系统上,文件名是 uuid
c7d43358-7532-4812-b828-b10b26694f0f.pdf
但我知道“通过默默无闻的安全”不是正确的解决方案......
如果可能的话,我想限制对每个帐户的文件的访问。我认为我可以做的一件事是将它们上传到 S3 并提供签名 URL,但如果可能的话,我现在想避免这样做。
我正在使用 Nginx/Django/Gunicorn/EC2/S3
还有哪些其他解决方案?
如果您提供小文件,您确实可以使用 Django 直接提供它们,将文件写入
HttpResponse
对象。
但是,如果您要提供大文件,您可能希望将该任务留给您的网络服务器,您可以使用 Nginx 上的
X-Accel-Redirect
标头(以及 Apache 和 Lighttpd 的 X-Sendfile
)让您的网络服务器为您提供文件.
您可以在此处在 Nginx 文档中找到有关标头本身的更多信息,并且您可以在此处找到有关如何在 Django 中使用标头的一些灵感。
完成通过 Django 视图发送文件后,使用 Django 的身份验证框架强制执行用户身份验证应该非常简单。
如何在视图级别强制执行
user==owner
,防止访问文件,将它们存储为 FileFields,并且仅在满足该条件时检索文件。
例如您可以在视图上使用
@login_required
decorator 仅在登录时才允许访问。这可以使用 request.user
进行细化以检查文件的所有者。 Django 文档 的用户身份验证部分可能会有所帮助。
正如您提到的,另一个选项是通过 S3 本身,在 Django 中生成 url,其中包含一个查询字符串,允许经过身份验证的用户访问以下载具有时间限制的特定 s3 对象。有关详细信息,请参阅s3 文档。之前曾在here on SO.
提出过类似的问题。我使用 django-private-files 取得了巨大成功,它在视图级别强制实施保护,并使用不同的后端来进行实际的文件传输。
要在使用 Nginx 提供文件时管理 Django 应用程序中的用户对静态文件的访问,您可以实现一个安全系统来控制访问。这是解决此问题的分步方法:
首先,配置Nginx以限制对静态文件的直接访问。这可以通过使用 Nginx 中的内部重定向和访问控制来完成。
编辑 Nginx 配置文件(例如 /etc/nginx/sites-available/your_site):
nginx
server {
listen 80;
server_name your_domain.com;
location /static/ {
internal;
alias /path/to/staticfiles/;
}
location /media/ {
internal;
alias /path/to/mediafiles/;
}
location /protected_static/ {
alias /path/to/staticfiles/;
add_header X-Accel-Redirect /static/;
}
location /protected_media/ {
alias /path/to/mediafiles/;
add_header X-Accel-Redirect /media/;
}
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
在此配置中:
/static/ 和 /media/ 位置被标记为内部,这意味着它们不能直接从外部访问。 /protected_static/ 和 /protected_media/ 位置充当这些内部位置的代理,添加 X-Accel-Redirect 标头以执行内部重定向。
在 Django 中,创建一个视图,在提供静态文件之前检查用户权限。该视图将生成 Nginx 可以处理的 URL。
from django.http import HttpResponse, Http404
from django.conf import settings
import os
def serve_protected_file(request, file_path):
# Check user permissions here
if not request.user.is_authenticated:
raise Http404
# Generate the X-Accel-Redirect header
response = HttpResponse()
response['Content-Disposition'] = 'attachment; filename="%s"' % os.path.basename(file_path)
response['X-Accel-Redirect'] = os.path.join('/protected_static/', file_path)
response['Content-Type'] = ''
return response
更新您的 urls.py 以指向新视图:
from django.urls import path
from . import views
urlpatterns = [
path('protected_static/<path:file_path>/', views.serve_protected_file, name='serve_protected_file'),
]
在您的模板中,使用安全 URL:
<a href="{% url 'serve_protected_file' file_path='path/to/your/file.jpg' %}">Download</a>
额外安全措施
基于令牌的访问:为了提高安全性,生成在一定时间后过期的临时访问令牌。 日志记录和监控:记录对受保护文件的访问并监控异常活动。
遵循这些步骤可确保静态文件受到保护并且只有授权用户才能访问。 Nginx 的内部重定向和 Django 的权限检查的结合使您可以安全地管理用户对 URL 的访问。