7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ファイルのPOST時にPHPで拡張子の偽装チェックを行う

Last updated at Posted at 2020-01-22

こんにちは!

クライアントサイドよりPOSTされたファイルに対して、ディレクトリトラバーサル対策等の他にも着目すべき点はありますが、今回は「クライアントサイドのフォームでPOSTしたファイルのバリデーション」のうち、「ファイルの拡張子の偽装チェック」を行うことに着目します!

そもそも拡張子の偽装とは何なのか


mv sample.png sample.jpg

上記例のように内部バイナリのコンバート処理を行うことなく、拡張子を変更することであります。

しかし、Hexとして上記ファイルを検閲すると、

hex.png

pngファイルと確認することの出来るマジックナンバーがバイナリヘッダーに存在しますね!

では、このファイル名上の拡張子がjpgで内部的にpngであるファイルをクライアントサイドのフォームよりPOSTすると、PHPではどういった挙動になるのか確認してみましょう!

サーバーサイドで拡張子が偽装されたファイルのバリデーションをする

まず前提条件として、下記のフィールドよりPOSTされたファイルを扱うとします。

<input type="file" name="up-file">

その際に、sample.png を sample.jpg にリネームしたファイルをPOSTします。
すると、

echo $_FILES["up-file"]["type"];

では、MIME-Typeとして

image/jpeg

を確認できるはずです。

これは、MIME-Type一覧ページで確認できる通り、jpgファイルとして認識されていることがわかる証拠です。

しかし、


$f_info = finfo_open(FILEINFO_MIME_TYPE); 
$mime = finfo_file(
    $f_info,
    $_FILES["up-file"]['tmp_name'] 
);
finfo_close($f_info); //念の為メモリ空間に開いたストリームの破棄を行う

echo $mime;

として、POSTされたファイルのバイナリからMIME-Typeを取得すると、


image/png

のように本来はpngファイルであることを確認できます。

まとめ

$_FILES["識別子"]["type"]

で確認出来るMIME-Typeは、ファイル名上の拡張子から推測されるものであることがわかりました!

なので、

  • ファイル名上の拡張子から推測できるMIME-Type
  • ファイルのバイナリヘッダーから推測出来るMIME-Type

の合致チェックを行って、よりセキュアにファイルのバリデーションを行おこうと思いました!

以下は、サンプルコードです!


$file = $_FILES["識別子"];

$file_mime_type = $file["type"];

$f_info = finfo_open(FILEINFO_MIME_TYPE);
$binary_mime_type = finfo_file(
    $f_info,
    $file['tmp_name']
);
finfo_close($f_info);

$is_same_mime_type = $file_mime_type === $binary_mime_type;

ありがとうございました!!!

追記

POSTされたファイルのHexをPHP上で確認する方法。


$binary = file_get_contents(
    $_FILES["識別子"]["tmp_name"]
);

echo bin2hex($binary);

bin2hex(正確にはBinary to Hex)でBinaryデータをHexにコンバートします!
上記コード中の


$_FILES["識別子"]["tmp_name"]

には、POSTされたファイルの一時的(temporary)なパスが文字列(String型)として格納されているだけなので、バイナリデータとして扱うためにfile_get_contentsをしています。

あとは、

  1. 16進数にコンバートされたバイナリヘッダーより拡張子の推測を行い、(参照
  2. 拡張子からMIME-Typeの推測を行う(参照

事ができます!

7
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?