PHP - 为什么要使用move_uploaded_file而不是rename?

3
在手册中,我看到说有关安全原因的内容,但是我没有完全明白有何问题情况。
这个函数用于确保由文件名指定的文件是有效的上传文件(也就是通过PHP的HTTP POST上传机制上传的)。如果文件是有效的,它将被移动到指定的文件名。
如果上传文件可能会向用户或甚至同一系统上的其他用户公开其内容,则此类检查尤为重要。
因此,它确保它是由PHP上传的,但如果不进行检查会发生什么?可能会泄露哪些信息以及如何泄露?
有人能解释一下吗?举个例子会更好。

文件的内容和文件名显然不能被忽略。想象一下,PHP 允许将文件上传到通过 HTTP 发布的 /img 文件夹中。在 PHP 进行进一步处理、保护、验证内容和名称、重命名之前,图像将已经可用。 - arkascha
@arkascha 但这不是我的问题。您可以验证所有必要的事情,然后使用rename而不是move_uploaded_file - HTMHell
但是,如果您只重命名文件,则该文件已经位于相同的物理位置。这可能会带来潜在的安全问题。请注意:这不一定是不安全的。但是,可能有些人会实现不安全的设置。这就是为什么选择了另一种解决方案。顺便问一下,这有什么关系吗? - arkascha
@arkascha 你的意思是什么?使用renamemove_uploaded_file都无所谓,文件都会上传到同一个临时文件夹。(rename还可以在不同驱动器之间移动文件)。这很重要,因为我想知道它可能会引起哪些安全漏洞。 - HTMHell
啊,好的,确实我最初理解你的问题是另一种方式。 - arkascha
如果这只是关于为什么使用特定函数而不是php的通用rename()函数,那么我假设该特定函数进行了额外的验证:移动/重命名的文件实际上是当前请求中上传的文件之一。但是正如我所说的:我只是假设。您必须查看实现以确保。 - arkascha
2个回答

2

一个PHP脚本可能会移动一些在运行时确定名称的文件(刚刚上传的临时文件的名称)。这个检查旨在确保编写不良的脚本不会暴露系统文件或包含认证密钥的文件。

假设我编写了一个脚本,允许您将图像上传到我的服务器,通过嵌入一些我提供的超可爱的猫咪gif来增强它,并再次下载它。为了跟踪您正在处理的图像,我将文件名嵌入请求URL中以供编辑按钮使用:

http://example.com/add-kitty.php?img=ato3508.png&add=kitty31.gif

或者我将同样的信息嵌入到cookie或POST数据中,错误地认为这样会使其更加安全。然后一些有进取心的脚本小子试着去获取它(或者使用POST/cookie的等效方法):

http://example.com/add-kitty.php?img=$2Fetc%2Fpasswd&add=kitty31.gif

看到了吗?那就是路径/etc/passwd,经过url编码。糟糕!你可能刚刚使你的/etc/passwd文件可以下载,并且中间还有一点小猫咪的声音。

显然这不是任何东西的完整工作漏洞,但我相信你已经明白了:函数move_uploaded_file会进行额外的检查,以保护您免受将意外文件名注入到您的代码中的攻击。


所以,如果我理解正确的话,在上传时它并没有保护任何东西,但是它可以通过不首先上传图像来帮助你防止显示图像时出现安全漏洞?(只有在你编码错误的情况下)那么,它是如何知道哪些是不良文件名?如果其中有一个 urlencode 后的斜杠呢? - HTMHell
不完全是。在用户上传图像之后,您将继续发送请求告诉服务器如何编辑它,然后将其发送回给您。这些后续请求可以进行微调,以欺骗服务器发送您实际上没有上传的内容。您(@HtmHell)说得对,正确编写的代码可以安全地工作,而无需使用此功能,但仍然有很多可以从中受益的代码。 - alexis

0

在这种情况下,安全问题是上传目录将对公众可见。

为了避免这种情况,您需要配置您的Web服务器(如Apache),使目录对公众不可见。

此外,每当您通过PHP脚本上传文件时,请使用混合字符重命名文件。

例如,您可以使用加密时间戳与实际文件名相结合。

处理文件上传似乎是常规的。您可以坚持使用这种方式来安全地处理文件上传。

编辑:

根据您在评论中提出的问题,此答案已进行编辑。

您需要在任何www目录中拥有现有文件,以使用rename($existing_old_file_name, $new_file_name)函数将其重命名。

move_uploaded_file($tmp_uploaded_file_name, $new_file_name)函数将上传的文件从临时目录移动到您在函数中指定的目标位置。


但是使用move_uploaded_file时也会遇到这些问题。我的问题是为什么不使用rename呢? - HTMHell
您需要在www目录中拥有一个现有文件,才能使用rename()函数重命名它。move_uploaded_file()函数将上传的文件从tmp目录移动到您在该函数中指定为第二个参数的目标位置。 - Wolverine
不,使用rename函数您还可以将文件从临时目录移动到目标文件夹,方法如下:rename($tmp_uploaded_file_name, $new_file_name) - HTMHell
就我所知,rename()函数无法正确上传图像文件,而且在函数的第一个参数中,您需要指定已上传的tmp文件名作为源的绝对tmp目录,目标可以是绝对路径或相对路径。 - Wolverine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接