以前の PHP バージョンでは、ファイルのアップロードは次のコードによって行われていた可能性が高くなります:
......
if (isset($_FILES['file'])) {
$tmp_name = $_FILES['file']['tmp_name'];
}
if (file_exists($tmp_name)) {
copy($tmp_name,$destfile);
}
......
しかし、tmp_name の内容が /etc/passwd などの機密情報として指定される場合、$_FILES['file'] 配列が偽造される可能性が非常に高くなります。コンテンツのセキュリティ上の問題が発生しやすい可能性があります。 PHP では、is_uploaded_file() と move_uploaded_file() を使用してこの問題を後のバージョンで解決しました。 is_uploaded_file() を使用すると、$_FILES['file']['tmp_name'] が存在するかどうかだけでなく、$_FILES['file' ][] もチェックされます。 'tmp_name'] はアップロードされたファイルであり、$_FILES['file']['tmp_name'] が PHP アップロードではないことを確認するとスクリプトの実行が終了するため、$_FILES 変数を偽造することは不可能になります。
偽造は不可能になったのでしょうか?多くのスクリプトでは、初期化部分に @extract($_POST) などの操作があり、レジスタ グローバルがオフになっている環境でもプログラムが実行し続けることができるようになっています。このような環境では、$_FILES 配列を簡単に偽造できます。 、元の $_FILES 配列を上書きすることもできますが、is_uploaded_file() と move_uploaded_file() を節約することはできないため、$_FILES 配列を完全に偽装することは依然として非常に困難です。ただし、Windows の PHP 環境でテストした場合、PHP の一時ファイルは C:WINDOWSTEMPphp93.tmp の形式であり、アップロードするとファイル名が C:WINDOWSTEMPphpXXXXXX.tmp の形式で変更されることがわかりました。 , XXXXXX は 16 進数で順番に増加します。つまり、今回アップロードした一時ファイル名が C:WINDOWSTEMPphp93.tmp であれば、次回は C:WINDOWSTEMPphp94.tmp となります。となるパターンがあります。ただし、現在のファイル名が不明な場合は、たとえば、一時ファイルを許可なくディレクトリにコピーしたり、ファイル システムで禁止されている文字をターゲット ファイルに含めたりすると、この情報が漏洩する可能性があります。もちろん、エラー抑制処理がなければ一時ファイル名は変更可能です。
では、is_uploaded_file() と move_uploaded_file() を省略するにはどうすればよいでしょうか? php の is_uploaded_file() 部分のコードを見てください:
PHP_FUNCTION(is_uploaded_file)
{
zval **path;
if (!SG(rfc1867_uploaded_files)) {
RETURN_FALSE;
}
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &path) != SUCCESS) {
ZEND_WRONG_PARAM_COUNT();
}
convert_to_string_ex(path);
if (zend_hash_exists(SG(rfc1867_uploaded_files), Z_STRVAL_PP(パス), Z_STRLEN_PP(パス)+1)) {
RETURN_TRUE;
} else {
RETURN_FALSE;
}
}
現在の rfc1867_uploaded_files ハッシュ テーブルから検索して、現在のファイル名が存在するかどうかを確認します。このうち、rfc1867_uploaded_files は、現在の PHP スクリプトの実行中にシステムと PHP によって生成されたファイル アップロードに関連する変数とコンテンツを保存します。存在する場合は、指定されたファイル名が今回実際にアップロードされたことを意味し、存在しない場合はアップロードされていないことを意味します。
PHP の非常に奇妙な機能は、アップロード フォームを送信すると、ファイルは PHP が処理する前に一時ディレクトリにアップロードされ、PHP スクリプトが終了するまで破棄されないことです。つまり、$_FILSE 変数を受け入れない PHP スクリプトにそのようなフォームを送信した場合でも、$_FILSE 変数は生成され、ファイルは最初に一時ディレクトリにアップロードされます。問題が発生します。次のスクリプトはこの問題を説明する可能性があります:
$a=$_FILES['attach']['tmp_name'];
echo $a.".... .. ......";
$file='C:\WINDOWS\TEMP\php95.tmp';
echo $file;
if(is_uploaded_file($file)) echo '. .. ...はい';
?>
ここで、C:\WINDOWS\TEMP\php95.tmp は、私が推測した一時ファイルの名前です。当時、このスクリプトをテストするときに必要だったのは、 1 つまたは 100 個のファイルをアップロードして、一時ファイルの 1 つが C:\WINDOWS\TEMP\php95.tmp という名前になるようにします。この時点でスクリプトに抽出操作がある場合、$_FILES 変数を簡単に偽造できます。そうじゃない? $_FILES 変数の偽造の役割は何なのかを知りたいかもしれません。PHP は、アップロードを処理する際に、元のプログラムで許可されていないファイル名を生成することができます。元のファイルに対して、basename() と同様の操作が実行されます。名前は、一度偽造できます。その後、ファイル名などに簡単に「ああ../ああ」などを追加できます。好きなものを付けてください
実際の使用方法は少し厳しいかもしれませんが、最終的にはphp の欠陥です、笑。