7

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;
  }
}

また、ファイル スクリプトをオフにする「images」フォルダに .htaccess ファイルを保存しているため、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

セキュリティ上の理由からこれで十分です。または、コードと Web サイトを保護するために他の手順を実行する必要があります。

4

5 に答える 5

7

最初に言うことは、Apache のmod_mimeでファイルの種類を確認することです。それ以外の場合は、JPEG ファイルであるという HTTP 要求を送信できます。Yeap!のようなファイル拡張子を信頼するだけです。拡張子は .jpg ですが、実際には JPEG データの代わりに PHP ソース コードを挿入し、後でサーバー上で PHP ソース コードを実行できます。

もう 1 つは、これらのイメージ タイプを実行しないように Apache を常に強制することです。ForceTypeディレクティブでそれを行うことができます。

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

編集:

底辺が見えませんでした。ファイルスクリプトをオフにすると、絶対に役立ちます。

于 2013-01-29T12:42:25.923 に答える
3

このコードは安全ですか?

PHP

要するに、いいえ、必ずしもそうではありません! コードでカバーされていない致命的な欠陥が 1 つありますが、絶望しないでください。これは非常に簡単に解決できます。

スクリプトはファイルの拡張子をテストしていますが、ファイルの MIME タイプをテストしていないため、さまざまな問題が発生する可能性があります。

この小さな脆弱性を除けば、コードはかなり安全です。

アパッチ

HTTP リクエストを JPEG のように偽造するのは非常に簡単です。PHP でこれを処理できますが、この脆弱性があらゆる角度からカバーされていることを確認する方が適切な場合があります。以下で説明するように、Apache の MOD_MIME モジュールを使用した簡単な修正を使用して、この欠陥を修正できます。

HTTPS -おそらく無関係

これらのファイルがクライアントとサーバーの間で傍受されることが心配な場合は、Web サイトで SSL 証明書を使用することがセキュリティの絶対に不可欠な部分です。これにより、クライアントとサーバー間のすべてのデータが暗号化されます。

ただし、単にサーバー側のことを心配している場合は、アドバイスはありますが、これは実際には必要ありません。

可能な解決策

finfo()機能_

このfinfo()関数はファイルの MIME タイプを返すため、ファイルが JPEG でアップロードできるかどうかを示します。

この機能の詳細については、こちらを参照してください。

代替のアップロード

個人的には、Colin Verot Upload Class を使用することを好みます。このクラスは非常に使いやすく、潜在的なセキュリティ問題をすべてカバーし、GD ライブラリを使用して幅広い拡張機能を備えており、常に維持されています。

こちらの Colin Verot のサイトにアクセスして、クラスをダウンロードして使用を開始してください。

アパッチMOD_MIME

Apache MOD_MIME モジュールは、サーバーに送信されるファイルの MIME タイプのチェックを強制します。

詳細については、こちらをご覧ください。

于 2013-01-31T09:40:32.983 に答える
1

コードは良いようで、何よりも答えが良いようです。セキュリティに関してもう1点追加したいだけです。

  • ドキュメント ルートの外部にあるディレクトリ (http 要求ではアクセスできない) にファイルを保存し、最初に適切な承認を確認するスクリプトを使用してファイルを提供する必要があります。
于 2013-01-31T12:51:32.700 に答える
0

サーバー上のファイルのすべての解釈をオフにしたので、残っているのはファイル名だけです。独自の名前を生成したり、ユーザーが提供した名前を適切にフィルタリングしたりすれば、何も心配する必要はありません。

まあ..ほとんど何もない。GD ライブラリにセキュリティ エラーがある可能性があるため、悪意のあるイメージを使用して、サイズ変更中に何か悪いことができる可能性があります。ただし、PHP から処理できるものではないため、サーバーを最新の状態に保ちます。

于 2013-01-30T03:44:19.337 に答える
-1

既存の PHP アップロード システムを使用してもかまわない場合、この jQuery/PHP アップロード フレームワークは非常に構成可能で驚くべきものです。

http://blueimp.github.com/jQuery-File-Upload/

于 2013-01-30T22:52:35.270 に答える