在Django中验证上传文件

24 投票
6 回答
9787 浏览
提问于 2025-04-15 16:05

我正在开发一个Django应用,里面有一个叫做Event的模型。这个Event可以有一些相关的照片、静态的html文件和pdf文件。

我想让一些可信的用户能够上传这些文件,但我对安全性有点担心,特别是我在Django文档中看到的一些内容,让我更加小心。

注意,每当你处理上传的文件时,必须仔细考虑你要把这些文件上传到哪里,以及它们是什么类型的文件,以避免安全漏洞。一定要验证所有上传的文件,以确保这些文件确实是你认为的那种。例如,如果你不加验证就让某人将文件上传到你网站的根目录下,那么他们可能会上传一个CGI或PHP脚本,并通过访问这个脚本的URL来执行它。千万不要允许这种情况发生。

我该如何验证不同类型的文件呢?我很想听听大家在处理这类问题时的经验,或者有没有进一步阅读的链接。我感觉html文件可能风险太大,如果是这样的话,我会把上传权限限制给管理员。

6 个回答

6

首先,你需要把上传的内容存放在一个不容易被直接下载的文件夹里。如果你的应用程序在 ~/www/ 这个目录下,可以考虑把数据放在 '~/data/' 里。

第二步,你需要判断用户上传的文件是什么类型,然后为每种文件类型制定规则。

不能仅仅根据文件的后缀名来判断文件的类型,所以可以使用类似 Fileinfo 的工具。然后针对每种文件类型,创建一个验证器。比如,ImageMagick 可以用来验证图片文件。为了更高的安全性,你可能还需要对像 PDF 和 Flash 文件这样的文件运行病毒扫描。对于 HTML 文件,你可能需要限制使用的标签。

我找不到 Python 里和 Fileinfo 模块相对应的东西,不过你可以执行 /usr/bin/file -i 来获取文件信息。大多数允许上传的系统会为每个文件创建一个内容名称或 ID。然后它们会使用 mod_rewrite 来解析 URL,并在磁盘上找到对应的内容。一旦找到内容,就会通过 sendfile 或类似的方式返回给用户。例如,在内容被批准之前,可能只有上传它的用户可以查看。

15

对于图片,你可以直接使用Python图像库(PIL)。

Image.open(filepath)

如果文件不是图片,就会出现错误。我对Python和Django还不太熟悉,所以可能还有其他人有更好的方法来验证图片。

20

所有的回答都在讨论如何验证文件。这几乎是不可能的。

Django的开发者并不是让你去验证文件是否能作为cgi文件执行。他们只是告诉你不要把这些文件放在会被执行的地方。

你应该把所有Django相关的东西放在一个专门的Django目录里。这个Django代码目录里不应该包含静态内容。不要把用户文件放在Django的源代码库里。

如果你使用的是Apache2,可以看看基本的cgi教程:http://httpd.apache.org/docs/2.0/howto/cgi.html

Apache2可能会设置为运行ScriptAlias文件夹里的任何文件。不要把用户文件放在/cgi-bin//usr/local/apache2/cgi-bin/文件夹里。

Apache2可能会根据AddHandler cgi-script的设置来服务cgi文件。不要让用户提交扩展名为.cgi.pl的文件。

不过,你确实需要清理用户提交的文件,以确保它们在其他用户的机器上安全运行提交的HTML对其他用户来说是不安全的。这不会伤害你的服务器。你的服务器只会把它返回给请求的人。找一个HTML清理工具吧。

另外,SVG可能是不安全的。它过去有过漏洞。SVG是一种包含javascript的XML文档,所以它可能会有恶意代码。

PDF文件...有点棘手。如果真的需要,你可以把它转换成图片,或者提供一个图片预览(让用户自己下载,风险自负),但这对使用它的人来说会很麻烦。

考虑建立一个允许的文件白名单。嵌入在gif、jpeg或png文件中的病毒看起来只会像是一个损坏的图片(或者无法显示)。如果你想谨慎一点,可以使用PIL把它们都转换成标准格式(嘿,你也可以检查文件大小)。清理过的HTML应该是可以的(去掉script标签并不复杂)。如果清理过程消耗了太多资源(或者你只是小心),你可以把它放在一个单独的服务器上,我想。

撰写回答