如何在Perl中限制CGI文件上传中的文件类型?

时间:2009-03-30 15:54:05

标签: perl cgi file-upload

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

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

完成

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

4 个答案:

答案 0 :(得分:6)

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

  

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

如果您确实想要这样做,请让用户上传文件,然后 然后使用像File::MimeInfo::Magic(或file(1)这样的内容 UNIX实用程序)猜测实际的文件类型。如果你不喜欢 文件类型,删除文件并向用户提供错误消息。

答案 1 :(得分: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可以包含客户端脚本,这些脚本将接管用户对站点的访问(跨站点脚本攻击)。

此时您可能想要在服务器端嗅探文件,例如使用'file'命令检查它是否包含'&lt; html&gt;'。但这注定要失败。 'file'命令不会像IE那样嗅探所有相同的HTML标记,而其他浏览器无论如何都会嗤之以鼻。准备一个“文件”声称不是HTML的文件是很容易的,但是IE仍会像对待它一样(具有安全 - 灾难影响)。

内容嗅探方法(例如'file')只会给你一种虚假的安全感。这是一种方便的工具,可以轻松猜测文件类型,有效安全措施。

此时你最后的绝望可能是:

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

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

  • 仅接受来自可信用户的上传。

答案 2 :(得分:2)

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

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

答案 3 :(得分:0)

试试这个:

$file_name = "file.txt";

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

$file_type = `$file_cmd`;

return 0 unless($file_type =~ /(ASCII|text)/i)