$_FILES[...]['size'] 可以伪造吗?

Ben*_*min 6 php security file-upload

有一个众所周知的警告,即不要信任通过 PHP ( $_FILES[...]['type']) 中的文件上传发送的 MIME 类型,因为这是由 HTTP 客户端发送的,因此可能被伪造。

文件名 ( ) 也有类似的警告$_FILES[...]['name'],该文件名由 HTTP 客户端发送,可能包含潜在的危险字符。

但是,我看不到文件大小 ( $_FILES[...]['size']) 是如何伪造的,因为它似乎不是请求有效负载的一部分,至少我在 Chrome 的开发工具中看不到它,其中有效负载看起来像:

------WebKitFormBoundarytYAQ3ap4cmAB46Ek
Content-Disposition: form-data; name="picture"; filename="picture.jpg"
Content-Type: image/jpeg
Run Code Online (Sandbox Code Playgroud)

原始文件名和 MIME 类型按预期出现在此处,但没有大小参数的迹象。

不过,我刚刚偶然发现了 Symfony 的UploadedFile实现,它将文件大小视为客户端发起的,因此不可信:

上传文件::getClientSize()

返回文件大小。它是从上传文件的请求中提取的。那么不应将其视为安全值。

文件大小是否可以成为请求有效负载的一部分,从而被伪造,或者它是否始终从 指向的实际文件推断出来$_FILES[...]['tmp_name'],因此始终可信?

Ben*_*min 6

正如@Dagon在评论中所建议的,我检查了rfc1867.c中的PHP源代码。

定义属性涉及的行[size]是:

[1042] wlen = write(fd, buff, blen);
       ...
[1056] total_bytes += wlen;
       ....
[1242] ZVAL_LONG(&file_size, total_bytes);
       ...
[1270] snprintf(lbuf, llen, "%s[size]", param);
       ...
[1275] register_http_post_files_variable_ex(lbuf, &file_size, ...
Run Code Online (Sandbox Code Playgroud)

我将其翻译为:

  • 第1042章临时文件以wlen大小块写入
  • wlen1056total_bytes
  • 第1242章 total_bytes分配给file_sizezval
  • 第1270...[size]1270lbuf
  • file_size1275lbuf章1275...[size]

因此,毫无疑问,唯一分配给的变量$_FILES[...]['size']是写入路径分配给的临时文件的实际字节数$_FILES[...]['tmp_name']

据我所知,没有办法伪造size属性