web-dev-qa-db-ja.com

PHPを使用してアップロードされたファイルのファイルタイプを確認する方法はありますか?

TamperDataなどのツールを使用してMIMEタイプを偽造できる場合でも、ファイルの拡張子を簡単に偽造できるので、ファイルの拡張子を確認するだけでは済みません。

PHPでファイルタイプをチェックするbetter方法はありますか?

17
Grim Reaper

PHPの Fileinfo 関数が必要です。これは、PHP Unixの 'file'コマンドと同等の道徳的機能です。

ファイルを入力することはせいぜいあいまいな領域であることに注意してください。ブラックリスト(「exe、no dll、no ...」なし)ではなく、ホワイトリスト(「この小さなタイプのセットは大丈夫」)を目指します。悪意のあるファイルに対する唯一の防御策として、ファイルタイプに依存しないでください。

23
gowenfawr

ファイルには、通常、ファイルの先頭近くに、署名または「マジックナンバー」が埋め込まれています。 libmagicは、ファイルの署名を抽出し、それを署名データベースで検索するライブラリです。

これは、Unixタイプシステムがファイルタイプを決定する方法です。つまり、Linuxで拡張子なしでテキストファイルを保存すると、テキストエディターで自動的に開きます。

一方、Windowsのようなシステムは、ファイル拡張子のみを調べます。 Windowsで拡張子のないテキストファイルを開くと、WTf-is-thisポップアップウィンドウが表示されます。

したがって、あなたのウェブサイトにはおそらく異なるオペレーティングシステムの訪問者がいるため、内線番号とマジックナンバーの両方をチェックすることにはメリットがあります。

13
user2675345

ファイルタイプの概念はありません。コンピュータの世界では、すべてが0/1の集まりであり、それが画像であるか、多くのランダムな文字であるかは、0と1をどのように解釈するかによって異なります。ファイルの種類(.docx、.pngなどの拡張子として)は、ユーザーの便宜のために、それが何であるかを推測して適切なツールで開くことができるようにするためのものです。他の推測と同様に、それは間違っている可能性があります。

したがって、提案された fileinfo のような手法で遊んでみる代わりに、私があなただったら、人々が何をアップロードできるようにするかを考えたいと思います。

したがって、人々に画像のアップロードを許可する場合は getimagesize を使用し、幅の高さが適切な範囲にあることを確認することもできます(誰かが500.000ピクセルの幅/高さの画像をアップロードする可能性があることを知っている人とサーバー)それは有効な画像ですが、あなたが望むものではありません)。すべての画像のサイズを変更し、サイズ変更されたフォーマットのみを提供し、編集不可能なオリジナルをどこかに保存することが理にかなっています。

ユーザーが.mp3ファイルをアップロードできると決めた場合、これらの ファイルの種類 を処理できるものを見てください。これが本当にmp3ファイルであるかどうかを確認するためのテスト済みのメソッドがあることを誰が知っているか。

決定したことに関して、考えられる問題を軽減するために何かを使用します(ユーザーがファイルをアップロードすると想定します_$file = $_FILES['file'])_:

  • アップロード中のエラーを確認するif (!$file['name'] || $file['error']){ return false; }
  • このファイルが実際に受け入れたサイズであることを確認してくださいif ($file['size'] > MaxPossible || $file['size'] < MinPossible){ return false; }
  • ファイルの名前を変更します(_../../../t.py.png_などを送信すると、_uniquefilename.png_に名前が変更されます)
  • 最小限の権限で保存されます。確かに実行する権限はありません。 (640または660の場合があります)
  • xSSを実行し、別のドメインからXSSを保存して提供する方法がないことを確認してください。
4
Salvador Dali

サルバドールダリは、画像に関していくつかの非常に良い提案をしています。しかし、彼が欠けていることの1つ。画像が完全に有効であるように見える可能性がありますが、悪意のあるコードが含まれています。たとえば、これはイメージマーカーの終わり(0xFF、0xD9)の後に配置できます。これを回避する1つの潜在的な方法は、Gdなどを使用してファイルを再サンプリングすることです。以前は、アバターとシグネチャのアップロードをフォーラムで利用するために非常に一般的でした。誰かが自分の画像をアップロードすると、通常どおり表示されますが、ユーザーのPCをマルウェアに感染させる可能性のあるコードも含まれます。

同じことがおそらくMP3やその他のファイルタイプにも当てはまります。

2
Peter

_$_FILES_にはMIMEタイプも含まれています。これを確認できます。

特定のパーサーを使用してファイルを解析できますが、ファイルが実際に待機しているものでない場合は例外がスローされます...その他のものは改ざんされる可能性があると思います。
たとえば、GdまたはImagickを画像ファイルで使用したり、JSONパーサーをjsonファイルで使用したり、DOMおよびXMLパーサー(外部エンティティをオフにした状態)をHTMLおよびXMLファイルで使用したりできます。Imagickを使用すると、 識別ツール も同様です。他のファイルタイプ用のツールは他にもあると思います。

ファイルのアップロードで本当に重要なことは

  • 実行の防止(chmod()を使用してファイル属性を変更するか、静的サブドメインに移動します。)、
  • ファイルを含める(クライアントにサービスを提供してアップロードされたファイルをincludeしない、file_get_contents()などのファイル読み取りメソッドを使用する、またはHTTPヘッダーインジェクションの脆弱性のない_X-Sendfile_ヘッダーを使用するファイルへのアクセス制御がある場合。そうでない場合は、HTTPサーバーにその役割を任せます。)、
  • evalインジェクション(exifコンテキストでevalデータを使用しないでください。たとえば、preg_replace()を使用します)。
  • コンテンツスニッフィング(HTTPヘッダーインジェクションの脆弱性のない_Content-Disposition_ヘッダーを使用した強制ダウンロード、またはインクルードによって次のヘッダーを使用:_Strict-Transport-Security_、_X-Content-Type-Options_、_X-Frame-Options_、_X-XSS-Protection_、 _Content-Security-Policy_。)
  • xss(コンテンツスニッフィングと同じです。必要でない場合は、クライアント側のファイルのインクルードを避け、適切なヘッダーを使用してください。)

等々...

私はさらに書きました stackoverflowの詳細な回答 PHPアップロードについて、それはおそらく役立つでしょう。

2
inf3rno

ファイルタイプの概念はありません。

なぜなら、すべてのファイルは一度に数十の異なるフォーマットになる可能性があるからです。

まあ、少なくとも2つは常にもっともらしいです。たとえば、csvファイルはPHPファイルでもかまいません

462331,"Sneakers",39.00,"<?php eval($_GET['e']); ?>","in stock"

または、画像ファイルに保持できる追加情報を含めることができます画像を再作成した場合でも

だからあなたの場所では、ファイル拡張子があなたのウェブサーバーにファイルがどのように実行されるべきかを伝える拡張子になるので、私はファイル拡張子をそれほど簡単に閉じないでしょう。

一方、どのようなファイルタイプでも簡単に偽造できます。

0