【问题标题】:How to reliable tell the uploaded file type (text or binary)?如何可靠地告诉上传的文件类型(文本或二进制)?
【发布时间】:2012-08-10 11:10:56
【问题描述】:

我有一个应用程序,用户应该能够上传各种各样的文件,但我需要知道每个文件是否可以安全地将其文本表示形式显示为纯文本。

使用python-magic点赞

m = Magic(mime=True).from_buffer(cgi.FieldStorage.file.read())

给我正确的 MIME 类型。

但有时,脚本的 MIME 类型是 application/*,因此仅查找 m.startswith('text/') 是不够的。

Another site 建议使用

m = Magic().from_buffer(cgi.FieldStorage.file.read())

并检查'text' in m。

第二种方法对于上传任意文件的集合是否足够可靠,或者有人可以给我另一个想法吗?

非常感谢。

【问题讨论】:

  • 检查文件扩展名是否足够好?
  • 如果你有一套相当明确的标准,我会避开file/magic,因为它的启发式有时会以特殊的方式失灵。如何检查没有长时间运行的不可打印字符,检查行长度是否正常,并在显示之前用实体替换任何看起来像 HTML 的内容?
  • @InbarRose,在这种情况下我不会相信用户的文件名...
  • @tripleee 检查不可打印的字符似乎是另一个信仰问题。你有什么建议吗?
  • @moschlar:检查行长并在文件的第一行中搜索 ascii bellow 0x20 - 永远不要相信用户输入。

标签: python file-upload mime-types mime python-magic


【解决方案1】:

玩了一会儿,我发现我可以正确使用Magic(mime_encoding=True)的结果!

我在我的 Dropbox 文件夹上运行了simple script,并按编码和扩展名对结果进行了分组,以检查是否存在违规行为。

但是通过查找'binary' in encoding 看起来确实很有用。

我想我会坚持下去,但谢谢大家。

【讨论】:

  • 只要您的代码仅在美国使用,这可能会起作用。
  • 查看输出:.tmp 是unknown-8bit。 .version 是 None。寻找binary 是不够的。相信我,我为国际客户编写过代码;没有简单的解决方案。 50 年的“简单解决方案”造成了混乱,这确保了这一点。 :-)
  • 您真的应该将其分组到第二列,以查看您获得的不同类型并将文件扩展名打印为列表。另外:当一个文件扩展名产生两种不同的 mime 类型时,检查您的代码打印的内容。
  • 我一起破解了一些东西并在我的 Dropbox 文件夹中运行它,结果如下:gist.github.com/3347601#file_types.txt 这对我来说看起来不错。有一些坏男孩,例如。 .pdf,但它是迄今为止我得到的最好、最简单和通用的解决方案......
【解决方案2】:

你的目标是什么?你想要真正的哑剧类型吗?出于安全原因,这很重要吗?还是“很高兴”?

问题是同一个文件可以有不同的 mime 类型。当脚本文件具有正确的#! 标头时,python-magic 可以确定脚本类型并告诉您。如果缺少标头,text/plain 可能是你能得到的最好的。

这意味着没有通用的“永远有效”的神奇解决方案(尽管模块的名称)。您将不得不坐下来思考您可以获得哪些信息、它的含义以及您希望如何处理它。

安全的解决方案是创建一个您接受的 mime 类型列表并使用它们进行检查:

allowed_mime_types = [ ... ]
if m in allowed_mime_types:

这意味着只接受完美匹配。这也意味着您的服务器将出于某种原因拒绝没有正确 mime 类型的有效文件(缺少标题,魔术无法识别文件,您忘记在列表中提及 mime 类型)。

或者换一种说法:如果你不在乎,为什么还要检查文件的 mime 类型?

[编辑]当你说

我需要知道每个文件是否可以安全地将其文本表示形式显示为纯文本。

那么这并不像听起来那么容易。首先,“文本”文件中没有存储编码,因此您需要知道用户在创建文件时使用的编码。这不是一项微不足道的任务。这样做有一些启发式方法,但是当使用 ISO 8859-1 和 8859-15 之类的编码(后者有欧元符号)时,事情会变得很棘手。

要解决此问题,您需要强制用户以特定编码保存文本文件(UTF-8 目前是最佳选择),或者您需要提供用户必须将文本粘贴到其中的表单.

使用表单时,用户可以查看文本是否正确编码(他们在屏幕上看到),他们可以解决任何问题,并且您可以确保浏览器向您发送使用 UTF-8 编码的文本。

如果您不能这样做,您唯一的选择是检查输入中 0x20 以下的任何字节,\r、\n 和 \t 除外。这是对“这是一个文本文档”的一个很好的检查。

但是当用户使用变音符号时(例如当您编写一个在全球范围内使用的应用程序时),这种方法最终会失败,除非您可以在用户端强制执行特定的编码(您可能无法做到,因为您没有这样做)不信任用户)。

[EDIT2] 因为你需要这个来检查实际的源代码:如果你想确保源代码是“安全的”,那么就解析它。大多数语言允许在不实际执行的情况下解析代码。这会给你一些真实的信息(因为解析器知道要寻找什么)并且你不需要做出疯狂的猜测:-)

【讨论】:

  • 我需要这些信息的主要原因实际上只是为了在 html 文本区域中显示文件的内容......
  • 查看我的编辑。您可以检查二进制字符,但这只会让您走到一半。
  • 我认为将 binary 检测为 mime_encoding 就像我在我的回答中写的那样做一些非常相似的事情!
  • 如果我告诉你我的应用程序的范围你会笑的:它是关于上传(或粘贴 - 我想支持这两种方法)源代码进行自动化测试。你不会期望那里有变音符号,对吧? - 原来德国学生喜欢它们...... -.- 无论如何,如果真的只有源代码,我可以简单地坚持下去并忽略二进制数据。但是课程老师也想支持PDF和图片提交...
  • 如果你想确保源代码是“安全的”,然后解析它。大多数语言允许在不实际执行的情况下解析代码。这会给你一些真实的信息(因为解析器知道要寻找什么)并且你不需要做出疯狂的猜测:-)
猜你喜欢
  • 2011-08-10
  • 2012-04-02
  • 2012-01-26
  • 1970-01-01
  • 2010-10-02
  • 2016-02-21
  • 2011-09-28
  • 2012-03-08
相关资源
最近更新 更多