【问题标题】:PHP temp file names for uploads colliding上传冲突的 PHP 临时文件名
【发布时间】:2009-03-10 19:22:01
【问题描述】:

当一个用户上传一个文件时,它会随机地被另一个用户的上传所取代,我终于找到了 PHP 和 tmp 文件名被重用的问题。有没有办法解决这个问题?有没有办法制作更好的随机名称?它似乎随着时间的推移而退化,因为随机文件名种子变弱了?这是 PHP 5.2.8 和 FreeBSD 7.0

这是一个日志,显示了相同的 tmp 文件名如何被另一个上传文件使用并被另一个上传文件覆盖:http://pastebin.com/m65790440

非常感谢任何帮助。我已经尝试解决这个问题超过 4 个月,并且随着时间的推移变得更糟。谢谢。

编辑:请记住,这不是 PHP 代码问题,这发生在它到达任何 PHP 代码之前,通过 $_FILES['name']['tmp_name'] 收到的文件在收到时不正确,并且追溯它在到达上传处理脚本之前被别人的上传覆盖了

【问题讨论】:

  • 问题是您的 tmp 目录还是您将文件复制/移动到的目录?
  • 我在使用 Freebsd 8 和 PHP 5.3 时遇到了同样的问题。为了重现,我有一个非常简单的上传脚本。对于 5 次测试,这里很可能会发生碰撞。这真的很糟糕。我真的不知道从哪里开始。如上所述,这个问题对 Google 来说也很困难。

标签: php file-upload temporary-files


【解决方案1】:

在 FreeBSD 7 的 libc 实现中将相关代码追踪到 _gettemp 之后,我不清楚文件 tmp_name 的内容如何可能无效。 (要跟踪它,您可以下载 PHP 5.2.8 的副本并阅读 main/rfc1867.c - 第 1018 行调用 main/php_open_temporary_file.c,从第 227 行开始的函数,它是从第 97 行开始的函数的主要工作,然而,它本质上只是系统上 mkstemp 的包装器,可在第 66 行(链接)的FreeBSD libc implementation 中找到,它使用_gettemp(与上面相同)实际生成随机文件名。但是@987654324 @ 在 BUGS 部分中提到 arc4random() function 不是可重入的。可能可能有 2 个同时请求进入关键代码部分并返回相同的 tmp_name - 我对此知之甚少Apache 如何与 mod_php 或 php-cgi 一起工作以在此处发表评论(尽管使用 FastCGI/php-cgi 可能有效 - 我目前无法成功评论)。

但是,针对最简单的解决方案,如果您没有完全体验到文件 tmp_name 本身无效,而是与其他上传的文件发生冲突(例如,如果使用 tmp_name 的文件名部分作为唯一性的唯一来源在存储的文件名中),由于birthday paradox,您可能会面临冲突。在another question 中,您提到要移动大约 5,000,000 个文件,在 still another question 中,您提到每天接收 30-40k 次上传。这让我觉得这是生日悖论碰撞的主要情况。 mktemp man page 提到(如果像 PHP 那样使用六个“X”)有 56,800,235,584 个可能的文件名(62 ** 6 或 62 ** n,其中 n =“X”的数量等)。但是,鉴于您有超过 500 万个文件,发生冲突的概率为 approximately 100%(另一个启发式建议您已经经历了大约 220 次冲突,如果 ((files*(files-1)) /2)/(62**6) 表示任何东西,其中文件 = 5,000,000)。如果这是您面临的问题(可能,if 没有向生成的上传文件名添加进一步的熵),您可以尝试类似move_uploaded_file($file['tmp_name'], UPLOADS.sha1(mt_rand().$file['tmp_name']).strrchr($file['name'], '.')) 的方法 - 想法是为随机文件名添加更多随机性,防止碰撞。另一种方法是在main/php_open_temporary_file.c 的第 134 行再添加两个“X”并重新编译。

【讨论】:

    【解决方案2】:

    听起来您的 PHP 安装或 PHP 内部用于生成随机文件名的任何系统调用都存在严重问题(很可能是 tempnam)。

    对于其他所有人:PHP 在处理用户代码之前在内部处理上传的文件。这些名称存储在 $_FILES['file']['tmp_name'] 中(其中 'file' 是表单上文件输入元素的(带引号的)名称)。

    【讨论】:

    • 是的,我相信你是对的,现在我需要弄清楚如何解决它=B
    • 我一直在查看是否可以在 Google 上找到任何内容,但我没有。如果将upload_tmp_dir设置为不同的目录,问题是否仍然存在?
    • 是的,刚刚测试过了,当upload_tmp_dir设置为不同的值时问题仍然存在,/var分区(文件上传到的位置)上设置的“noatime”会对此产生影响?
    • 我不这么认为,但我必须检查一下。另外,我在 pastebin 中注意到这些文件上的组设置为轮...使用不同临时目录的另一个原因。
    • 关于轮组问题:nabble.com/…
    【解决方案3】:

    PHP 是否在 apache 下运行,如 mod_php

    您可以尝试create a per-process temporary upload directory 其名称包含您的php getmypid(),然后ini_set 您的PHP 进程'upload_tmp_dir 到 那个目录。如果为每个请求生成一个新的 php 进程,这将不起作用。

    【讨论】:

    • 有没有办法覆盖 PHP 命名文件上传的方式?
    • 否,但您可以覆盖(在运行时)转储临时文件的临时目录
    【解决方案4】:

    上传文件后将其移至用户目录。应该删除那些临时文件。

    【讨论】:

    • 这是正确的修复方法。 PHP 的临时上传文件仅在处理脚本将它们移动到它们实际所属的位置所需的时间内保持在原处。
    • 在某些时候,PHP 的政策变成如果您没有移动/重命名临时文件,则在请求结束时删除它们,因此如果您升级到该版本之后,您的整个当前机制也会中断.
    • 他们正在被移动。 PHP上传处理脚本从$_FILES['name']['tmp_name']接收到的文件开头错误
    【解决方案5】:

    我建议您使用 GUID 生成器生成文件名,因为您得到了这么多。

    【讨论】:

    • 有没有办法覆盖 PHP 命名文件上传的方式?截至目前,php 使用“phpxxxxx”模式
    猜你喜欢
    • 2018-11-20
    • 1970-01-01
    • 1970-01-01
    • 2013-03-15
    • 2013-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多