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

3
我注意到有一个用户试图通过上传头像图片来创建漏洞。当一个用户向我报告说他们收到了诺顿杀毒软件的提示,显示“HTTP可疑可执行图像下载”的警告时,这个问题被发现。这个警告是指该用户的头像图片。我认为他们没有实际窃取信息或者其他任何东西,但如果漏洞长期存在,这是可能的。我使用PHP上传图像文件,并检查正在上传的文件是否是png、jpg、bmp或gif格式的。
以下是检查是否是图片的代码:
$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;
}
4个回答

9

无法防止恶意文件的上传。您需要关注的是如何处理这些文件。

重新保存图像文件等建议是徒劳无功的。攻击者可以通过调整位序,使其在已知的图像压缩器运行后按照攻击者想要的顺序排列,从而绕过此类操作。

有很多方法可以将图像和恶意文件组合在一起。恶意文件可以是可执行文件,也可以只包含JavaScript代码,由浏览器解释。此外,如果文件不是图像类型,您应该如何重新保存它们呢?

在处理文件上传时,必须注意以下几点。

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

  • 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.

  • 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.

  • 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.

  • 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).

  • 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.


3

最简单的解决方案是重新采样图片。获取一个简单的图像处理库(GD),加载并重新保存图片,这应该有效地剥离任何可执行内容,或者如果图片只是一个重命名的exe,则会直接失败。


重新保存是一种过度操作。如果它是被掩盖的exe文件,在打开时会失败。 - Andrey
2
这不是过度操作。某些文件格式(主要是gif)允许您将非图像数据嵌入文件中。唯一可靠地摆脱它的方法是加载并重新保存。 - ircmaxell
是的,重新保存的目的是为了删除额外嵌入的数据,如果图像既是图像又是可执行文件。 - Aren

1
使用imagecreatefromjpeg(以及其他的imagecreatefrom*函数)来检查传递的数据是否是真实的图像。exe文件将无法通过检查。

2
getimagesize可能是更好的选择,因为它不会加载资源。 - buggedcom

0

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