web-dev-qa-db-ja.com

PHP画像アップロードのセキュリティチェックリスト

アプリケーションに画像をアップロードするスクリプトをプログラミングしています。次のセキュリティ手順は、アプリケーションをスクリプト側から安全にするのに十分ですか?

  • .httaccessを使用して、アップロードフォルダー内での実行を無効にするPHP=.
  • ファイル名に文字列「php」が含まれている場合、アップロードを許可しないでください。
  • 拡張子のみを許可:jpg、jpeg、gifおよびpng。
  • 画像ファイルタイプのみを許可します。
  • 2つのファイルタイプの画像を許可しません。
  • イメージ名を変更します。
  • ルートディレクトリではなくサブディレクトリにアップロードします。

これは私のスクリプトです:

 $filename=$_FILES['my_files']['name'];
 $filetype=$_FILES['my_files']['type'];
 $filename = strtolower($filename);
 $filetype = strtolower($filetype);

 //check if contain php and kill it 
 $pos = strpos($filename,'php');
 if(!($pos === false)) {
  die('error');
 }




 //get the file ext

 $file_ext = strrchr($filename, '.');


 //check if its allowed or not
 $whitelist = array(".jpg",".jpeg",".gif",".png"); 
 if (!(in_array($file_ext, $whitelist))) {
    die('not allowed extension,please upload images only');
 }


 //check upload type
 $pos = strpos($filetype,'image');
 if($pos === false) {
  die('error 1');
 }
 $imageinfo = getimagesize($_FILES['my_files']['tmp_name']);
 if($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg'&& $imageinfo['mime']      != 'image/jpg'&& $imageinfo['mime'] != 'image/png') {
   die('error 2');
 }
//check double file type (image with comment)
if(substr_count($filetype, '/')>1){
die('error 3')
}

 // upload to upload direcory 
 $uploaddir = 'upload/'.date("Y-m-d").'/' ;

if (file_exists($uploaddir)) {  
} else {  
    mkdir( $uploaddir, 0777);  
}  
  //change the image name
 $uploadfile = $uploaddir . md5(basename($_FILES['my_files']['name'])).$file_ext;



  if (move_uploaded_file($_FILES['my_files']['tmp_name'], $uploadfile)) {
 echo "<img id=\"upload_id\" src=\"".$uploadfile."\"><br />";
  } else {
   echo "error";
  }

新しいヒントは大歓迎です:)

61
usef_ksa

Gd(またはImagick)を使用して画像を再処理し、処理された画像を保存します。他のすべてはただ 楽しい ハッカーの退屈。

編集:rrが指摘したように、アップロードにはmove_uploaded_file()を使用します。

後期編集:ところで、アップロードフォルダーについては非常に制限したいでしょう。これらの場所は、多くのエクスプロイトが発生する暗いコーナーの1つです。これは、あらゆる種類のアップロードとプログラミング言語/サーバーに有効です。チェック https://www.owasp.org/index.php/Unrestricted_File_Upload

33
Halil Özgür

画像ファイルのセキュリティテストについては、4つのレベルのセキュリティを考えることができます。それらは:

  • レベル1:拡張子を確認します(拡張子ファイルの末尾は)
  • レベル2:MIMEタイプの確認($file_info = getimagesize($_FILES['image_file']; $file_mime = $file_info['mime'];)
  • レベル3:最初の100バイトを読み取り、次の範囲のバイトがあるかどうかを確認します:ASCII 0-8、12-31(10進数)。
  • レベル4:ヘッダー内のマジックナンバー(ファイルの最初の10〜20バイト)を確認します。ここからいくつかのファイルヘッダーバイトを見つけることができます: http://en.wikipedia.org/wiki/Magic_number_%28programming%29#Examples

注:画像全体の読み込みは遅くなります。

12
tanjir

XSS警告

もう一つの非常に重要な発言。ブラウザでHTMLとして解釈される可能性のあるものを提供/アップロードしないでください。

ファイルはドメイン上にあるため、そのHTMLドキュメントに含まれるjavascriptはすべてのCookieにアクセスし、何らかのXSS攻撃を可能にします。

攻撃シナリオ:

  1. 攻撃者は、すべてのCookieをサーバーに送信するJSコードを含むHTMLファイルをアップロードします。

  2. 攻撃者はリンクをメール、PM、または単に他のサイトのiframe経由でユーザーに送信します。

最も安全なソリューション:

アップロードされたコンテンツをサブドメインまたは別のドメインでのみ利用可能にします。この方法では、Cookieにアクセスできなくなります。これは、Googleのパフォーマンスのヒントの1つでもあります。

https://developers.google.com/speed/docs/best-practices/request#ServeFromCookielessDomain

7
Rok Kralj

$ _FILES ['my_files'] ['tmp_name']でも「is_uploaded_file」を実行することもできます。 http://php.net/manual/en/function.is-uploaded-file.php を参照してください

6
rr.

アップロードディレクトリに新しい.htaccessファイルを作成し、次のコードを貼り付けます。

php_flag engine 0
RemoveHandler .phtml .php .php3 .php4 .php5 .php6 .phps .cgi .exe .pl .asp .aspx .shtml .shtm .fcgi .fpl .jsp .htm .html .wml
AddType application/x-httpd-php-source .phtml .php .php3 .php4 .php5 .php6 .phps .cgi .exe .pl .asp .aspx .shtml .shtm .fcgi .fpl .jsp .htm .html .wml

アップロードするファイルの名前を必ず変更してください+タイプ、コンテンツなどの確認は忘れてください

6
jloa

関連する質問で投稿した内容を繰り返します。

Fileinfo functions (以前のバージョンのPHPではmime_content_type())を使用してコンテンツタイプを検出できます。

抜粋形式PHP古いMimetype拡張に関するマニュアル。現在はFileinfoに置き換えられています。

このモジュールの関数は、ファイル内の特定の位置で特定のマジックバイトシーケンスを探すことにより、ファイルのコンテンツタイプとエンコーディングを推測しようとします。これは防弾アプローチではありませんが、使用されているヒューリスティックは非常に良い仕事をしています。

getimagesize()も良い仕事をするかもしれませんが、あなたが実行している他のチェックのほとんどはナンセンスです。たとえば、文字列phpがファイル名に許可されない理由。名前にphp文字列が含まれているという理由だけで、PHPスクリプトに画像ファイルを含めるつもりはありませんか?


イメージの再作成に関しては、ほとんどの場合、使用するライブラリに脆弱性がなくなるまでセキュリティが向上します。

では、どのPHP拡張機能は安全な画像の再作成に最適ですか? CVEの詳細 ウェブサイトをチェックしました。該当するトリオはこれらの拡張機能であると思います。

  1. Gd (6つの脆弱性)
  2. ImageMagick (44個の脆弱性)
  3. Gmagick (12の脆弱性)

比較から、Gdはセキュリティの問題が最も少なく、かなり古いため、Gdが最適だと思います。そのうち3つは重要ですが、ImagMagickとGmagickのパフォーマンスは向上していません... ImageMagickは非常にバグが多いようです(少なくともセキュリティに関しては)。

5
doc

セキュリティが非常に重要な場合、データベースを使用してファイル名を保存し、ファイル名を変更し、ここでファイルの拡張子を.myfileのようなものに変更し、ヘッダー付きの画像を送信するためのphpファイルを作成できます。 phpはより安全で、imgタグでblowのように使用できます。

<img src="send_img.php?id=555" alt="">

また、アップロードする前にEXIFでファイル拡張子を確認します。

2
Mohamad Rostami

最良ユーザーが画像をアップロードするときにウェブサイトを安全に保つ方法は次の手順を実行することです:

  • 画像の拡張子を確認してください
  • この関数「getimagesize()」で画像サイズを確認してください
  • この後、関数「file_get_contents()」を使用できます
  • 最後に、データベースにfile_Contentを挿入する必要があります。これが最善の方法だと思います! ndあなたの意見は何ですか?
2
Hamza Ouha

PHPでファイルを安全にアップロードできるようにする に対する最も簡単な答えは:常にドキュメントルートの外部にファイルを保存します。

例:ドキュメントルートが/home/example/public_htmlの場合、ファイルを/home/example/uploadedに保存します。

Webサーバーによって直接実行される範囲からファイルを安全に保護した状態で、訪問者がアクセスできるようにする方法はいくつかあります。

  1. PHP、Perlなどのスクリプトを決して実行しない静的コンテンツを提供するための個別の仮想ホストを設定します。
  2. ファイルを別のサーバー(安価なVPS、Amazon S3など)にアップロードします。
  3. それらを同じサーバーに保持し、PHPスクリプトを使用してリクエストをプロキシし、ファイルが読み取り専用で実行可能ではないことを確認します。

ただし、このリストのオプション1または3を使用し、アプリケーションにローカルファイルインクルードの脆弱性がある場合、ファイルアップロードフォームは 依然として攻撃ベクトル です。

2

私はphp-upload-scriptを使用して、アップロードされたファイルごとに新しいランダムな4バイト番号を作成し、ファイルのコンテンツとこれらの4バイトをXOR(必要に応じて何度も繰り返す)し、最後に4ファイルを保存する前のバイト数。

ダウンロードするためには、ファイルから4バイトを再度切り捨てる必要があり、コンテンツはそれらと再びXORされ、結果がクライアントに送信されます。

このようにして、サーバーに保存したファイルが実行可能でないこと、またはアプリケーションにとって意味を持たないことを確信できます。さらに、ファイル名を保存するための追加のデータベースは必要ありません。

これに私が使用しているコードは次のとおりです。

アップロード:

        <?php
            $outputfilename = $_POST['filename'];
            $inputfile = $_FILES["myblob"]["tmp_name"];
            $tempfilename="temp.tmp";

            if( move_uploaded_file($inputfile, $tempfilename) ) {
                $XORstring = random_bytes(4);

                $tempfile=fopen($tempfilename, "r");
                $outputfile=fopen($outputfilename, "w+");
                flock($outputfilename, LOCK_EX);

                fwrite($outputfilename, $XORbytes1);

                while ( $buffer = fread($tempfile, 4) ) {
                    $buffer = $buffer ^ $XORstring;
                    fwrite($outputfilename, $buffer);
                }

                flock($outputfilename, LOCK_UN);

                fclose($tempfile);
                fclose($outputfile);

                unlink($tempfilename);
            }

            exit(0);
        ?>

ダウンロード:

        <?php
            $inputfilename = $_POST['filename'];
            $tempfilename = "temp.tmp";

            $inputfile=fopen($inputfilename, "r");
            $tempfile=fopen($tempfilename, "w+");
            flock($tempfile, LOCK_EX);

            $XORstring = fread($inputfile, 4);

            while ( $buffer = fread($inputfile, 4) ) {
                $buffer = $buffer ^ $XORstring;
                fwrite($tempfile, $buffer);
            }

            flock($tempfile, LOCK_UN);

            fclose($inputfile);
            fclose($tempfile);

            readfile($tempfile);
            unlink($tempfile);

            exit(0);
        ?>
0
Max M.

画像ファイルの場合、名前を変更した後にファイルの許可を変更して、実行されないようにすることもできます(rw-r--r--)

0
Jesus