【问题标题】:PHP File upload security - keeping the original file namePHP文件上传安全 - 保留原始文件名
【发布时间】:2012-04-12 23:37:09
【问题描述】:

我希望允许网站 (PHP) 的注册用户上传文件(文档),这些文件将公开供下载。 在这种情况下,我保留文件的原始名称是一个漏洞吗? 如果是一个,我想知道为什么,以及如何摆脱它。

【问题讨论】:

    标签: php security file-upload filenames


    【解决方案1】:

    虽然这是一个老问题,但在查找“安全文件名”时,它在搜索结果列表中的排名出奇地高,因此我想扩展现有答案:

    是的,几乎可以肯定这是一个漏洞。

    如果您尝试使用原始文件名存储文件,您可能会遇到几个问题:

    • 文件名可以是保留文件名或特殊文件名。如果用户上传一个名为 .htaccess 的文件,告诉网络服务器将所有 .gif 文件解析为 PHP,然后上传一个带有 <?php /* ... */ ?> GIF 注释的 .gif 文件,会发生什么?
    • 文件名可以包含../。如果用户上传一个名为“名称”../../../../../etc/cron.d/foo 的文件会怎样? (这个特殊的例子应该被系统权限捕获,但是知道你的系统读取配置文件的所有位置吗?)
      • 如果运行Web 服务器的用户(我们称之为www-data)配置错误并且有一个shell,那么../../../../../home/www-data/.ssh/authorized_keys 怎么样? (同样,这个特殊的例子应该被 SSH 本身(并且可能文件夹不存在)保护起来,因为 authorized_keys 文件需要非常特殊的文件权限;但是如果您的系统设置为默认情况下限制文件权限(棘手!),那么这不会是问题。)
    • 文件名可以包含x00 字节或控制字符。系统程序可能无法按预期响应这些 - 例如一个简单的ls -al | cat(不是我知道你为什么要执行它,而是一个更复杂的脚本可能包含一个最终归结为这个的序列)可能会执行命令。
    • 文件名可以以.php 结尾,并在有人尝试下载文件时执行。 (不要try blacklisting extensions。)

    处理此问题的方法是自己滚动文件名(例如,文件内容或原始文件名上的md5())。如果您绝对必须尽最大努力允许原始文件名,请将文件扩展名列入白名单mime-type 检查文件,然后将文件列入白名单 字符可用于文件名。

    或者,您可以在存储文件时自己滚动文件名,并在人们用来下载文件的 URL 中使用(尽管如果这是一个文件服务脚本,您应该避免无论如何,让人们在此处指定文件名,因此没有人下载您的../../../../../etc/passwd 或其他感兴趣的文件),但将原始文件名保存在数据库中以在某处显示。在这种情况下,您只需要担心 SQL 注入和 XSS,这是其他答案已经涵盖的基础。

    【讨论】:

      【解决方案2】:

      文件的名称可能会泄露潜在的敏感信息。一些公司/人对文档使用不同的命名约定,因此您最终可能会得到:

      • 作者姓名 (court-order-john.smith.doc)
      • 公司名称 (sensitive-information-enterprisename.doc)
      • 文件创建日期(letter.2012-03-29.pdf)

      我想你明白了,你可能会想到人们在他们的文件名中使用的一些其他信息。

      根据您的网站是什么,这可能会成为一个问题(考虑 wikileaks 是否发布了在文件名中包含原始来源的泄露文档)。

      如果您决定隐藏文件名,则必须考虑有人将可执行文件作为文档提交的问题,以及如何确保人们知道他们正在下载的内容。

      【讨论】:

      • 嗯,很好,我跳过了“公开可用”部分。
      • 我完全不担心包含敏感信息的文档的名称,在我的情况下,这是用户的问题。我只是担心人们以可以利用某些漏洞的方式命名他们的文件。此外,我希望能够保留原始名称,因为当有人下载​​文件时,如果它被命名为“resume_3242354543”,他将无法知道它是什么文件,这是安全的,但不是用户友好的。我正在寻找安全性和可用性之间的折衷方案。
      • @teum 在这种情况下,如果您将名称存储在强类型变量中并在显示之前进行编码,您会没事的
      • 一开始我觉得不值一提,但它是在PHP环境中的。所以我绝对可以忘记“强类型变量”。
      【解决方案3】:

      这取决于您存储文件名的位置。如果您将名称存储在数据库中,在严格类型的变量中,然后在将其显示在网页上之前进行 HTML 编码,不会有任何问题。

      【讨论】:

      • 是的,文件名存储在数据库中,但这是我们正在谈论的 PHP 网站,所以不存在强类型变量...对不起,我忘了提到 PHP因为我认为问题与语言无关,但显然我错了:)
      • @teum 有关 SQL 安全,请参阅此 SO 帖子 stackoverflow.com/questions/60174/…,有关 XSS 预防请参阅此 SO 帖子 (stackoverflow.com/questions/1336776/…) 以开始
      • 我已经在使用 PDO 并过滤我的输入,所以我想一切都很好?
      • @teum 那我想不出别的了。
      猜你喜欢
      • 2018-08-19
      • 1970-01-01
      • 1970-01-01
      • 2015-06-09
      • 2020-02-16
      • 2011-01-09
      • 2017-03-12
      • 2020-06-20
      • 2016-04-27
      相关资源
      最近更新 更多