【问题标题】:How can I check uploaded files extension?如何检查上传的文件扩展名?
【发布时间】:2014-11-10 02:47:10
【问题描述】:

如何检查以下代码中上传的文件扩展名(我已经写了文件类型检查)?我想防止上传带有错误扩展名的图像文件,例如 *.jpg.exe。

我的代码:

<?php

class Uploader {

    private $fileName;
    private $fileData;
    private $destination;

    public function __construct($key){
        $this->fileName = $_FILES[$key]['name'];
        $this->fileData = $_FILES[$key]['tmp_name'];
    }

    public function saveIn($folder){
        $this->destination = $folder;
    }

    public function save(){

        $folderWriteAble = is_writable($this->destination);
        if($folderWriteAble && (exif_imagetype($this->fileData) == IMAGETYPE_JPEG)){
            $name = "$this->destination/$this->fileName";
            $success = move_uploaded_file($this->fileData, $name);
        } else {
            trigger_error("cannot write to $this->destination");
            $success = false;
        }

        return $success;

    }

} 

【问题讨论】:

标签: php forms security file-upload web


【解决方案1】:

如果您在您的服务器上运行 linux,我会使用返回文件真实 mime 类型的命令 file 检查文件内容类型。比你可以确定的内容是什么(在大多数情况下)。

那个程序使用那个魔法字节。最初的想法是检查第一个视图字节并检查文件是否包含已知模式,例如“MZ”用于 Windows 可执行文件或“‰PNG”用于 png 文件。然而,file 程序除了第一视图字节的基本集合之外,还做了更多的事情。


根据 cmets,您担心错误,例如双文件扩展名。我会说不要考虑它,只需重命名该文件,最好使用一些随机名称。如果您担心有人只是计算一些文件编号来查看未发布的图像,这也可能会有所帮助。

【讨论】:

  • 我想阻止上传带有 *.jpg.exe 等双扩展名的图像文件。我已经用 exif_imagetype() 检查了文件类型。就像有人想上传一个扩展名错误的有效图像文件:realImage.jpg.exe。如果他这样做,exif_imagetype() 返回 IMAGETYPE_JPEG
  • 因为它是有效的 jpg 图片,只是扩展名错误。
  • @NorbertKlár 好的,我现在明白了。你需要自己检查一下。但是,我建议重命名来自客户的所有文件。它们很可能包含用户不喜欢发布的数据。始终牢记从安全角度出发那里的一切都是邪恶的,所以只要重命名该文件,当它有效时;-)
  • @NorbertKlár 欢迎您,还请记住,我可以将../evil_idea.jpg 之类的名称命名为,这可能会在上层目录中输出文件。我不相信php会默认解析出来......
【解决方案2】:

我认为您已经在 (exif_imagetype($this-&gt;fileData) == IMAGETYPE_JPEG) 上这样做了,但是这里有一个非常好的讨论:https://security.stackexchange.com/questions/57856/is-there-a-way-to-check-the-filetype-of-a-file-uploaded-using-php

【讨论】:

    【解决方案3】:

    使用 getimagesize 检查文件中的前三位。请注意, $_FILES 不安全,因为它读取扩展名(人们当然可以更改),而 getimagesize 读取权限位。

    用法:

    $image = getimagesize($_FILES['image']['tmp_name']);
    
    $filetype = $image['mime'];
    

    希望对你有帮助

    【讨论】:

      【解决方案4】:

      我知道这不一定能回答您的具体问题,但防止“PHP 图像”被“执行”的一个好方法是从不执行 PHP 脚本且仅提供静态图像的地方提供图像(即:nginx,如果配置正确)。 它甚至可以是一个外部 CDN,或者只是一个不运行 php 的简单目录。

      话虽如此,你也可以试试:

      1- Make sure file type is (jpg, gif or png)
      2- Make sure dimensions are numbers
      3- Make sure file size does not exceed allowed size
      4- Make sure file is not executable by anyone else (proper chmod settings are important in shared environment).
      5- Rename and convert all uploads through imagemagick to jpg (or your desired format)
      

      使用 GD 库测试你上传的图片是否为 jpg,此外,检查部分上传的图片是否也返回 false:

      $image = @imagecreatefromjpeg($this->fileData);
      if(!$image) { imagedestroy($image); return false; } // file is not a jpg
      else { imagedestroy($image); return true; } // file is a jpg
      

      如果您可以使用 exec(),您还可以调用 unix 文件实用程序来检查二叉签名。

      // verify that the file is a jpg
      $mime = "image/jpeg; charset=binary";
      exec("file -bi " . $this->fileData, $out);
      if ($out[0] != $mime) {
          // file is not a jpg
          ...
      

      如果您安装了 ClamAV,您还可以使用 exec 命令检查病毒:

      exec("clamscan --stdout " . $this->fileData, $out, $return);
      if ($return) {
          // file is infected
          ...
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-19
        • 2011-06-21
        相关资源
        最近更新 更多