フォームからファイルアップロードでのセキュリティ対策まとめ
お金 | 仕事 | 勉強 | プライベート | 健康 | 心
プログラミング関連のコンテンツ
C言語/C++入門 | Ruby入門 | Python入門 | プログラミング全般
ファイルアップロードの処理をPHPで書いていたところなので、それにまつわるセキュリティ関連を書いてみます。
PHPでフォームを用いてのファイルアップロードは、処理自体は容易に実装できます。
ファイルのアップロードに限らず、ウェブアプリケーションで難しいのは、セキュリティへの対策だと思います。
本質的なロジックの部分ではないせいか、個人的には若干面白さを感じにくい部分ではありますが、ウェブに公開する以上はセキュリティ対策は必須です。
ファイルアップロードの流れ
まずは、PHPでのファイルアップロード処理のおおまかな流れを把握から。以下のサイトを参考に。
ファイルのアップロード | PHP Labo で基本的な流れのソースは出来上がりなので、簡単この上ない。
ポイントを列挙すると・・
1. formタグを method="post" enctype="multipart/form-data" で作成(HTMLフォーム側)
2. inputタグを type="file" にしたフィールドを作成(HTMLフォーム側)
3. $_FILESでアップロードされた一時ファイルのデータを受け取る(PHPでの処理側)
4. is_uploaded_file()でファイルがHTTPアップロードされたかどうかを確認(PHPでの処理側)
5. move_uploaded_file()で一時ディレクトリから保存ディレクトリに移動(PHPでの処理側)
<input type="file" name="upfile"> と作成した場合、$_FILES["upfile"]は以下のような配列構造として受け取ります。
$_FILESは、POST経由のファイルアップロードを扱う、特殊なグローバル変数なので注意する。
$_FILES["upfile"] => Array ( [name] => "元のファイル名" [type] => "ファイルのMIMEタイプ" [tmp_name] => "一時ファイル名" [error] => "エラーコード(正常時は0)" [size] => "ファイルのサイズ" )
入門書籍のサンプルコードなどでも、同じようなものが多いです。
ただし、これはファイルアップロード処理の本質だけを表現した最低限のコードであると考えます。
セキュリティへの対策
そのまま運用するのはちょっとまずくて、セキュリティ対策をいくつか行わなければなりません。
データがvalid(正当である)かどうかを確かめる処理を、かっこよくバリデーション処理と言ったりもします。
この書籍はPHPでのセキュリティ対策がテーマの書籍ですが、他言語の場合でも、PHPの言語特有な部分以外は、同様なアプローチで応用がきくと思います。
ウェブアプリケーションのセキュリティに関する攻撃法と防御法が体系的にまとめてある、あまり他に類を見ない良書です。
頁100, 102, 103 163, 199, 205 あたりに、ファイルアップロードへのセキュリティ対策が書いてあります。
この本を参考にして、ファイルアップロードに関するセキュリティ対策をまとめておきます。
サンプルスクリプトは書籍を参考か、PHPサイバーテロの技法 – 読者サポート・正誤表を参考にできます。
考えられる脆弱性と対策
1. アップロードしたファイルが実行される
公開ディレクトリに元のファイル名と拡張子でアップロードの場合、ファイルを実行される恐れがある。
対策:
・非公開ディレクトリにアップロードされたファイルを保存する。
・公開ディレクトリにアップロードの場合、拡張子を外して、ファイル名をランダムに変更する。
・画像の場合、ファイル名の情報である$_FILES[]['name']から拡張子を調べ、ホワイトリストで許可指定。
└サーバーサイドでの実行可能な拡張子の設定も考慮の必要がある。
└getimagesize()関数で、拡張子とファイルの中身が一致しているか確認。
└ImageMagickでリサイズ、形式コンバートなどの処理を挟む。
2. XSS、Script Insertion
$_FILES[]['name']、$_FILES[]['type']などは自己申告のデータであり、telnet接続などから任意に設定できる。
JavaScriptコードでさえも利用されうるので、これらの変数を出力する際にはエスケープをしっかりと行う。
3. $_FILES変数によるSQLインジェクション
$_FILES由来の変数を用いてSQLを組み立てるときは、SQLインジェクションにも注意する。
テーマがちょっと別なので、SQLインジェクションについて詳細は省略。
$_FILES変数からのアプローチ
$_FILES[]['name'] の拡張子チェック
公開ディレクトリにアップロードの場合、.phpなどが実行される恐れがある。
非公開フォルダにアップロードしたファイルを保存する。
拡張子のチェックはホワイトリストで行う。アップロード可能にする拡張子のファイルだけを許可する。
サーバーサイドで実行可能な拡張子のファイルは、アップロードを許可しない。
アップロードされたファイルの拡張子を変更する。
$_FILES[]['type'] のチェック
$_FILES[]['type']だけに頼ったチェックは危険である。
telnet接続などでMIME_Typeは簡単に偽装できる。
$_FILES[]['tmp_name'] の移動チェック
move_upload_file()を用いて、$_FILES[]['tmp_name']のテンポラリファイルを移動しているか。
PHP: move_uploaded_file – Manual
bool move_uploaded_file ( string $filename , string $destination )
この関数は、filename で指定されたファイルが (PHP の HTTP POST アップロード機構によりアップロードされたという意味で) 有効なアップロードファイルであるかどうかを確認します。 そのファイルが有効な場合、destination で指定したファイル名に移動されます。
この種の確認は、アップロードされたファイルに関して何でもできる場 合には、その内容をユーザ、または同じシステム上の他のユーザにさえ 暴かれる可能性があるため、特に重要です。
$_FILES[]['type']、$_FILES[]['name']は自己申告のデータ
telnet接続などでこれらは自由に設定でき、JavaScriptでさえ記述できる。
これらのデータを出力する際はエスケープを行い、XSSやScript Insertion対策を行う。
おまけ、htmlspecialchars()の落とし穴
のP52に書いてあるのですが、htmlspecialchars()の落とし穴に注意。
リンクなどURL指定タグ、scriptタグ, styleタグの内側に外部変数を使う場合は、別処理が必要。
<a href="<?php echo $url ?>"> <img src="<?php echo $url ?>" /> <form action="<?php echo $url ?>" method="get"> <meta http-equiv="refresh" content="3; url=<?php echo $url ?>" />
などのコードで、$urlが外部由来の場合、”javascript:”で始まる文字列ではないことを確認する必要がある。
安易に、htmlspecialchars()を適用するだけでは、JavaScriptの実行を防げない。
URL指定が、”javascript:”で開始すると、任意のJavaScriptコードを実行できてしまう。
また、scriptタグ、styleタグ内に外部からの変数が入るのも注意。
<script><?php echo $script ?></script> <style><?php echo $style ?></style>
こういった設計は、設計自体を避けるようにする。
以上、ファイルアップロード処理に関するセキュリティ対策の大枠をまとめてみました。
なにか不足している点、間違っている点ありましたら、ご指摘お願いします。
- - 関連記事 -
- strpos() や strcmp() など間違えやすいif文での判定
- htmlentities() と htmlspecialchars() の違い
- PHPの内部エンコードと出力文字コード、スクリプト文字コード
- PHPのデバッグ・xdebugをxamppで有効にする
- CakePHPの日本語対応、国際化
- コマンドラインでPHPが起動できない
- 直接ファイルが実行されたときだけ起動するスクリプト
- ディレクトリを探索してリンク一覧表示
- PHPとRubyのコードの書き方を比較
- コメントアウトの使い分けと、/*** ~ ***/とか// — を単語登録
- PHPでvar_dump()を使ったお手軽デバッグコード
- プログラミング練習問題をPHPで解いてみた
- CakePHPはMVCかつフルスタックのフレームワーク
- PHP5のクラス定義とオブジェクトのおさらい
- フレームワークCakePHPにチャレンジ
- sort・asort・ksort 配列を並べ替える関数
- foreach構文
- PHPの配列
- strcmp関数
- strcasecmp関数