1

我正在使用 CGI 来允许用户上传一些文件。我只是希望能够上传 .txt 或 .csv 文件。如果用户上传任何其他格式的文件,那么我希望能够发出错误消息。

我看到这可以通过javascript完成:http: //www.codestore.net/store.nsf/unid/DOMM-4Q8H9E

但是有没有更好的方法来实现这一点?Perl 中是否有一些功能允许这样做?

4

4 回答 4

6

您链接到的网站上的免责声明很重要:

注意:这并不完全是万无一失的,因为人们可以在上传文件之前轻松更改文件的扩展名,或者做一些其他的诡计,例如“LoveBug”病毒。

如果你真的想这样做,让用户上传文件,然后使用File::MimeInfo::Magic(或file(1)UNIX 实用程序)之类的东西来猜测实际的文件类型。如果您不喜欢该文件类型,请删除该文件并向用户显示错误消息。

于 2009-03-30T16:01:00.677 回答
3

我只是希望能够上传 .txt 或 .csv 文件。

听起来很容易,不是吗?它不是。然后还有一些。

简单的方法是在将文件存储到文件系统之前测试文件是否以“.txt”或“.csv”结尾。在您让用户提交的文件名靠近文件系统的任何位置之前,这应该是对文件名允许包含的内容进行更深入验证的一部分。

因为在某些平台(尤其是 Windows)上,关于文件名中可以​​包含什么内容的规则很复杂,所以通常最好使用已知良好的名称和扩展名独立创建自己的文件名。

在任何情况下,都不能保证浏览器会向您发送一个具有可用名称的文件,即使确实如此,也不能保证该名称的末尾会有“.txt”或“.csv”,即使它是文本或 CSV 文件。(某些平台根本不使用扩展名进行文件输入。)

虽然您可以尝试嗅探文件的内容以查看它可能是什么类型,但这是非常不可靠的。例如:

<html>,<body>,</body>,</html>

可以是纯文本、CSV、HTML、XML 或各种其他格式。最好让用户明确控制他们正在上传的文件类型(或每种类型使用一个文件上传字段)。

现在这里是它变得非常讨厌的地方。假设您已接受上传并将其存储为 /data/mygoodfilename.txt,并且 Web 服务器正确地将其作为 Content-Type 'text/plain' 提供。您认为浏览器将其解释为什么?纯文本?你应该很幸运。

问题是浏览器(主要是 IE)不信任您的 Content-Type 标头,而是嗅探文件的内容以查看它是否看起来像其他东西。将上述代码片段作为纯文本提供,IE 会很乐意将其视为 HTML。这可能是一个大问题,因为 HTML 可以包含将接管用户对站点的访问的客户端脚本(跨站点脚本攻击)。

此时,您可能很想在服务器端嗅探文件,例如使用“文件”命令来检查它不包含“<html>”。但这注定要失败。'file' 命令不会像 IE 那样嗅探所有相同的 HTML 标签,并且其他浏览器无论如何都会以不同的方式嗅探。准备一个“文件”声称不是 HTML 的文件非常容易,但 IE 仍会将其视为它(具有安全灾难影响)。

诸如“文件”之类的内容嗅探方法只会给您一种错误的安全感。这是用于松散猜测文件类型的便利工具,而不是有效的安全措施。

在这一点上,你最后绝望的可能性是:

  • 从单独的主机名提供所有用户上传的文件,以便脚本注入攻击无法窃取您的主站点的凭据;

  • 通过 CGI 包装器提供所有用户上传的文件,添加标题“Content-Disposition:附件”,以便浏览器不会尝试直接显示它们;

  • 只接受来自受信任用户的上传。

于 2009-03-30T17:47:19.207 回答
2

在 unix 上,最简单的方法是建议使用 JRockway。如果不在 unix 上,那么您的选择是有限的。您可以检查文件扩展名并检查内容以进行验证。我假设您只需要“* 分隔值”文本文件的特定情况。因此,其中一个 Text::CSV::* 模块可能有助于验证文件是您要求的类型。

此操作的安全性是另一个蜡球。

于 2009-03-30T23:22:16.810 回答
0

尝试这个:

$file_name = "file.txt";

$file_cmd  = "file \"$file_name"\";

$file_type = `$file_cmd`;

return 0 unless($file_type =~ /(ASCII|text)/i)
于 2009-03-31T00:52:28.903 回答