阻止上传可执行图像 (PHP)

2022-01-09 00:00:00 image upload security php

我注意到一个用户试图通过上传头像图像来创建漏洞利用.当用户向我报告说他们从诺顿防病毒软件收到HTTP 可疑可执行图像下载"通知时发现了这一点.此警告引用了用户的头像图像.我不认为他们实际上在窃取信息或类似的事情上取得了任何成就,但我认为如果洞开得足够长,这是可能的.我使用 PHP 上传图片文件,并检查上传的文件是 png、jpg、bmp 还是 gif.

It has come to my attention that a user has been trying to create an exploit through avatar image uploads. This was discovered when a user reported to me that they were getting a notice from their Norton Anti-virus saying "HTTP Suspicious Executable Image Download." This warning was referencing the user's avatar image. I don't think they had actually achieved anything in the way of stealing information or anything like that, but I assume it could be possible if the hole is left open long enough. I use PHP to upload the image files, and I check if the file being uploaded is a png, jpg, bmp, or gif.

这是检查它是否是图像的代码:

This is the code that checks if it is an image:

$allow_types = array('image/jpeg', 'image/png', 'image/gif', 'image/jpg', 'image/png', 'image/bmp', 'image/bitmap');
if (in_array($this->tmp_image['type'], 
$this->allow_types)) {
   return true;
}

推荐答案

没有办法阻止恶意文件的上传.相反,您需要关心的是如何处理这些文件.

There is no way to prevent uploading of malicious files. What you need to care about instead is how you handle those files.

重新保存图像文件等建议注定失败.在已知的图像压缩器运行后,可以通过对位进行排序以使它们按照攻击者想要的顺序来绕过这种操作.

Suggestions such as re-saving the image file are doomed. It is possible to bypass such manipulation by ordering the bits so that they are in the order the attacker wants after a known image compressor has run.

有很多方法可以组合图像和恶意文件.恶意文件可能是可执行文件,或者仅包含可由浏览器解释的 JavaScript.此外,您应该如何重新保存不是图像类型的文件?

There are so many ways to combine images and malicious files. A malicious file could be an executable, or just contain JavaScript that gets interpret by a browser. Besides, how are you supposed to re-save files that are not type of image?

在处理文件上传时,必须注意以下事项.

When handling file uploads, one must take care of the following.

  • 限制每个用户上传的字节数,以免您的服务器空间不足.

  • Limit the amount of bytes to upload per user so your server won't run out of space.

限制每个用户上传的文件数量,这样您的服务器就不会用完 inode.

Limit the amount of files to upload per user so your server won't run out of inodes.

将文件存储在文档根目录之上,这样它们就无法直接访问.

Store the files above your document root so that they aren't directly accessible.

通过 PHP 代理脚本提供您的文件,编写如下内容:

Serve your files through a PHP-proxy script, write something like:

$data = file_get_contents('/home/account/files/file.png');
header('Content-Type: image/png');
header('Content-Length: '. strlen($data));
header('X-Content-Type-Options: nosniff');
echo $data;

  • 重命名上传的文件,使其具有完全随机的名称,不带扩展名.如果您需要存储文件名(和扩展名/类型),请将详细信息存储在数据库中.

  • Rename uploaded files to have a completely random name without an extension. If you need to store the filename (and extension/type), store the details in the database.

    如果需要,仅在用户有权拥有文件时提供文件.

    If needed, serve files only when the user has a permission to have it.

    永远不要包含/执行您上传的文件.这意味着 PHP 中没有 include 或 require.没有包含它们的 HTML 脚本标签或样式表标签.没有 Apache Include 命令包括它们.以此类推.

    Never include/execute the files you uploaded. This means no include or require in PHP. No HTML script tags or stylesheet tags including them. No Apache Include commands including them. And so forth.

    如果可能,请提供其他来源的文件.这消除了 Flash 出现的主要问题.使用不同的端口、域名或 IP 地址也可以.从子域提供服务是危险的,并且使用 IP 地址实现会稍微困难一些(即,您不能通过域提供文件,只能通过 IP 提供文件,并且不能通过 IP 提供站点,而是通过域提供).

    If at all possible, serve the files from other origin. This eliminates origin issues that occur with Flash mostly. Using a different port, a domain name or an IP-address is also fine. Serving from sub-domains is dangerous and with IP-addresses the implementation gets slightly harder (i.e., you can't serve files via the domain, only via IP and you can't serve the site via IP, but via the domain).

    小心 LFI 和 RFI.在 fopen()read() 等函数中使用文件名之前重命名文件名,并根据需要验证/清理任何目录值.

    Beware of LFI and RFI. Rename the filenames before using the filename within functions like fopen(), read(), etc. and validate/sanitize any directory values as needed.

  • 相关文章