php - 在 php 和 htaccess 中上传图像的安全方法

标签 php image-uploading

我在互联网上找到了以下用于在 php 中安全上传图片的代码。

我想知道它涵盖了所有可能的图片上传攻击方式。

define('MAX_SIZE_EXCEDED', 101);
define('UPLOAD_FAILED', 102);
define('NO_UPLOAD', 103);
define('NOT_IMAGE', 104);
define('INVALID_IMAGE', 105);
define('NONEXISTANT_PATH', 106);

class ImgUploader
{
  var $tmp_name;
  var $name;
  var $size;
  var $type;
  var $error;
  var $width_orig;
  var $height_orig;
  var $num_type;
  var $errorCode = 0;
    var $allow_types = array(IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG);

  function __construct($fileArray)
  {
    foreach($fileArray as $key => $value)
    {
      $this->$key = $value;
    }
    if($this->error > 0)
    {
      switch ($this->error)
      {
        case 1: $this->errorCode = MAX_SIZE_EXCEDED; break;
        case 2: $this->errorCode = MAX_SIZE_EXCEDED; break;
        case 3: $this->errorCode = UPLOAD_FAILED; break;
        case 4: $this->errorCode = NO_UPLOAD; break;
      }
    }
    if($this->errorCode == 0)
    {
      $this->secure();
    }
  }

  function secure()
  {
    //$this->num_type = exif_imagetype($this->tmp_name);
    @list($this->width_orig, $this->height_orig, $this->num_type) = getimagesize($this->tmp_name);

    if(filesize($this->tmp_name) > 1024*1024*1024*5) // allows for five megabytes.  Change this number if need be.
    {
      $this->errorCode = MAX_SIZE_EXCEDED;
      return false;
    }

    if (!$this->num_type)
    {
      $this->errorCode = NOT_IMAGE;
        return false;
    }
    if(!in_array($this->num_type, $this->allow_types))
    {
      $this->errorCode = INVALID_IMAGE;
      return false;
    }
  }

  function getError()
  {
    return $this->errorCode;
  }

  function upload_unscaled($folder, $name)
  {
    return $this->upload($folder, $name, "0", "0");
  }

  function upload($folder, $name, $width, $height, $scaleUp = false)
  {
    // $folder is location to be saved
    // $name is name of file, without file extention
    // $width is desired max width
    // $height is desired max height

    if($this->errorCode > 0)
      return false;

    // deal with sizing
    // if image is small enough to not scale, or upload_unscaled() is called, don't scale
    if((!$scaleUp && ($width > $this->width_orig && $height > $this->height_orig)) || ($width === "0" && $height === "0"))
    {
      $width = $this->width_orig;
      $height = $this->height_orig;
    }
    else
    {
      // if height diff is less than width dif, calc height
      if(($this->height_orig - $height) <= ($this->width_orig - $width))
        $height = ($width / $this->width_orig) * $this->height_orig;
      else
        $width = ($height / $this->height_orig) * $this->width_orig;
    }

    // Resample
    switch($this->num_type)
    {
      case IMAGETYPE_GIF: $image_o = imagecreatefromgif($this->tmp_name); $ext = '.gif'; break;
      case IMAGETYPE_JPEG: $image_o = imagecreatefromjpeg($this->tmp_name); $ext = '.jpg'; break;
      case IMAGETYPE_PNG: $image_o = imagecreatefrompng($this->tmp_name); $ext = '.png'; break;
    }

    $filepath = $folder.(substr($folder,-1) != '/' ? '/' : '');
    if(is_dir($_SERVER['DOCUMENT_ROOT'].$filepath))
      $filepath .= $name.$ext;
    else
    {
      $this->errorCode = NONEXISTANT_PATH;
      imagedestroy($image_o);
      return false;
    }

    $image_r = imagecreatetruecolor($width, $height);
    imagecopyresampled($image_r, $image_o, 0, 0, 0, 0, $width, $height, $this->width_orig, $this->height_orig);

    switch($this->num_type)
    {
      case IMAGETYPE_GIF: imagegif($image_r, $_SERVER['DOCUMENT_ROOT'].$filepath); break;
      case IMAGETYPE_JPEG: imagejpeg($image_r, $_SERVER['DOCUMENT_ROOT'].$filepath); break;
      case IMAGETYPE_PNG: imagepng($image_r, $_SERVER['DOCUMENT_ROOT'].$filepath); break;
    }

    imagedestroy($image_o);
    imagedestroy($image_r);

    return '/'.$filepath;
  }
}

我还有一个 .htaccess 文件存储在“images”文件夹中,它关闭了文件脚本,因此没有人可以执行 photos 文件夹中的脚本。

<Files ^(*.jpg)>
order deny,allow
deny from all
</Files>
Options -Indexes
Options -ExecCGI 
AddHandler cgi-script .php .php3 .php4 .php5 .phtml .pl .py .jsp .asp .htm .shtml .sh .cgi

出于安全原因,这样做是否足够,或者我必须采取一些其他步骤来保护我的代码和网站。

最佳答案

我要说的第一件事是用 Apache 的 mod_mime 检查文件类型,否则我可以发送一个 HTTP 请求,上面写着我是JPEG 文件! 您只需相信文件扩展名,例如 Yeap!你有 .jpg 扩展名,但实际上我可以注入(inject) PHP 源代码而不是 JPEG 数据,稍后我可以在你的服务器上执行 PHP 源代码。

另一件事是始终强制 Apache 不运行任何这些图像类型。您可以使用 ForceType 指令来做到这一点。

<FilesMatch "(?i)\.jpe?g$">
    ForceType image/jpeg
</FilesMatch>

编辑:

我没有看到底线。关闭文件脚本绝对有帮助。

关于php - 在 php 和 htaccess 中上传图像的安全方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14434517/

相关文章:

php - laravel putFileAs 路径错误

node.js - NodeJS+Multer 上传图片到服务器?

javascript - 在哪里从 cordova 应用程序上传文件以免费访问文件?

javascript - React JS 图像 uploader |更改背景图片

php - Paypal ipn 监听器 feof() : 30 is not a valid stream resource

java - 开始使用 Ledger API

php - 使用 PHP 动态生成二维码

php - 在 Woocommerce 3 中对购物车商品使用条件 has_term() 函数

javascript - DropzoneJS 将文件选择限制为一个文件,但允许后续上传

android - 将图像发送到 Node 服务器并调用 OCR microsoft vision API