- ベストアンサー
PHP で動的ファイル出力
PHP 猛勉強中です、またお世話になりますm( __ __ )m ドキュメントルート外に置いたイメージファイルを HP からリンクして表示できるように readfile 関数を使った PHP ファイルを作成しようと思っています。 readfile.php に対して URL クエリーでhttp://hoge/readfile.php?name=hage&ext=jpg のような感じで呼び出したいと思っています。 ※ name はファイル名、 ext は拡張子です。 [readfile.php] <?php $_name = ""; $_ext = ""; if(isset($_GET["name"]) === true && isset($_GET["ext"]) === true){ // null byte 対策 $_name = delete_nullbyte($_GET["name"]); $_ext = delete_nullbyte($_GET["ext"]); // ディレクトリトラバーサル対策 $_name = str_replace(".", "", @htmlspecialchars($_name, ENT_QUOTES, "UTF-8")); $_ext = str_replace(".", "", @htmlspecialchars($_ext, ENT_QUOTES, "UTF-8")); }else{ exit(); } $_file_path = "/home/xxx/img/" . $_name . "." . $_ext; // ファイル存在確認 if(file_exists($_file_path) === false){ exit(); } // MimeType 取得 $_ext_type = substr($_file_path, -3); $_mime_type = ""; if(strcasecmp($_ext_type, "jpg") === 0){ $_mime_type = "image/jpeg"; _out_file($_file_path, $_mime_type); }else{ exit(); } ///////////////////////////////////////////////// // ファイル出力 function _out_file($file_path, $mime_type) { // ファイル名取得 $_fname = @basename($file_path); // ファイルストリーム取得 header('Content-Type: ' . $mime_type); header("Content-Disposition: inline; filename='" . $_fname . "'"); readfile($file_path); } ///////////////////////////////////////////////// // null byte 除去メソッド function delete_nullbyte($str) { if(is_array($str) === true){ return ""; } return str_replace("\0", "", $str); } ?> 色々作業を進めるうちに「null byte 攻撃」や「ディレクトリトラバーサル攻撃」などの言葉が耳に入ってきてセキュリティ的に不安を感じています。 自分なりに調べて上記のようなコーディングをしましたが、果たして問題が無いのか、それとももっとたくさん考えなくてはならないのか、先輩方の意見が聞きたく質問させていただきました。 よろしくお願いしますm( __ __ )m
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
脆弱性の詳しい解説は、以下などをじっくり読んで貰うとして http://www.atmarkit.co.jp/fsecurity/rensai/webhole01/webhole01.html 画像に限らず、せっかく隠しディレクトリーにおいてあるファイル名をurlのクエリに含めたり、postさせたりするよりは、コード化した方が安全です。 つまり、対象ファイル名すべてを配列に入れておき、画像名の指定は、配列番号で行うといったことです。
その他の回答 (1)
- yambejp
- ベストアンサー率51% (3827/7415)
とりあえずreadfile()はバイナリセーフではないので、 きちんと開いて、読みだして、閉じるほうがよいでしょう。 また、ファイル名でアクセスするのは管理上も面倒ばかり多いので idをつかってアクセスするような方法に変えた方がいいと思います (であればだいぶセキュリティ問題も限定できるでしょうし)
お礼
回答ありがとうございます。 ファイル名でのアクセスについては No1 の回答者の方も言っている通りあまり良い実装ではないようですね・・改善してみます。 readfile() を使わないということは、fopen、fclose で読み込むと言うことでしょうか?
お礼
回答ありがとうございます。 なるほど。確かに、おっしゃるとおりですね。 もう一度設計を見直してファイル名を外に出さないように考えてみます。