アプリケーションに画像をアップロードするスクリプトをプログラミングしています。次のセキュリティ手順は、アプリケーションをスクリプト側から安全にするのに十分ですか?
これは私のスクリプトです:
$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";
}
新しいヒントは大歓迎です:)
Gd(またはImagick)を使用して画像を再処理し、処理された画像を保存します。他のすべてはただ 楽しい ハッカーの退屈。
編集:rrが指摘したように、アップロードにはmove_uploaded_file()
を使用します。
後期編集:ところで、アップロードフォルダーについては非常に制限したいでしょう。これらの場所は、多くのエクスプロイトが発生する暗いコーナーの1つです。これは、あらゆる種類のアップロードとプログラミング言語/サーバーに有効です。チェック https://www.owasp.org/index.php/Unrestricted_File_Upload
画像ファイルのセキュリティテストについては、4つのレベルのセキュリティを考えることができます。それらは:
($file_info = getimagesize($_FILES['image_file']; $file_mime = $file_info['mime'];)
注:画像全体の読み込みは遅くなります。
もう一つの非常に重要な発言。ブラウザでHTMLとして解釈される可能性のあるものを提供/アップロードしないでください。
ファイルはドメイン上にあるため、そのHTMLドキュメントに含まれるjavascriptはすべてのCookieにアクセスし、何らかのXSS攻撃を可能にします。
攻撃者は、すべてのCookieをサーバーに送信するJSコードを含むHTMLファイルをアップロードします。
攻撃者はリンクをメール、PM、または単に他のサイトのiframe経由でユーザーに送信します。
アップロードされたコンテンツをサブドメインまたは別のドメインでのみ利用可能にします。この方法では、Cookieにアクセスできなくなります。これは、Googleのパフォーマンスのヒントの1つでもあります。
https://developers.google.com/speed/docs/best-practices/request#ServeFromCookielessDomain
$ _FILES ['my_files'] ['tmp_name']でも「is_uploaded_file」を実行することもできます。 http://php.net/manual/en/function.is-uploaded-file.php を参照してください
アップロードディレクトリに新しい.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
アップロードするファイルの名前を必ず変更してください+タイプ、コンテンツなどの確認は忘れてください
関連する質問で投稿した内容を繰り返します。
Fileinfo functions (以前のバージョンのPHPではmime_content_type())を使用してコンテンツタイプを検出できます。
抜粋形式PHP古いMimetype拡張に関するマニュアル。現在はFileinfoに置き換えられています。
このモジュールの関数は、ファイル内の特定の位置で特定のマジックバイトシーケンスを探すことにより、ファイルのコンテンツタイプとエンコーディングを推測しようとします。これは防弾アプローチではありませんが、使用されているヒューリスティックは非常に良い仕事をしています。
getimagesize()
も良い仕事をするかもしれませんが、あなたが実行している他のチェックのほとんどはナンセンスです。たとえば、文字列php
がファイル名に許可されない理由。名前にphp
文字列が含まれているという理由だけで、PHPスクリプトに画像ファイルを含めるつもりはありませんか?
イメージの再作成に関しては、ほとんどの場合、使用するライブラリに脆弱性がなくなるまでセキュリティが向上します。
では、どのPHP拡張機能は安全な画像の再作成に最適ですか? CVEの詳細 ウェブサイトをチェックしました。該当するトリオはこれらの拡張機能であると思います。
比較から、Gdはセキュリティの問題が最も少なく、かなり古いため、Gdが最適だと思います。そのうち3つは重要ですが、ImagMagickとGmagickのパフォーマンスは向上していません... ImageMagickは非常にバグが多いようです(少なくともセキュリティに関しては)。
セキュリティが非常に重要な場合、データベースを使用してファイル名を保存し、ファイル名を変更し、ここでファイルの拡張子を.myfileのようなものに変更し、ヘッダー付きの画像を送信するためのphpファイルを作成できます。 phpはより安全で、imgタグでblowのように使用できます。
<img src="send_img.php?id=555" alt="">
また、アップロードする前にEXIFでファイル拡張子を確認します。
最良ユーザーが画像をアップロードするときにウェブサイトを安全に保つ方法は次の手順を実行することです:
PHPでファイルを安全にアップロードできるようにする に対する最も簡単な答えは:常にドキュメントルートの外部にファイルを保存します。
例:ドキュメントルートが/home/example/public_html
の場合、ファイルを/home/example/uploaded
に保存します。
Webサーバーによって直接実行される範囲からファイルを安全に保護した状態で、訪問者がアクセスできるようにする方法はいくつかあります。
ただし、このリストのオプション1または3を使用し、アプリケーションにローカルファイルインクルードの脆弱性がある場合、ファイルアップロードフォームは 依然として攻撃ベクトル です。
私は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);
?>
画像ファイルの場合、名前を変更した後にファイルの許可を変更して、実行されないようにすることもできます(rw-r--r--)