2012-05-08 12 views
0

私は自分のユーザーに保護されたファイルを提供するURLを持っています。このPHP関数はファイルトランスバーサルから保護しますか?

ファイル名は、名前に関係なくファイルをアップロードするときにアプリケーションによって書き換えられ、データベースに保存されます。だから私はそれが含まれていることはありません知っている「/」または「..」

ファイル名は次のとおりです。 『USER_ID』 _ 『USER_ID』と 『RANDOMMD5』 .FILE_EXT =現在のユーザーIDと 『RANDOM MD5』にログインし、正確にそれ。

これは私の関数は、ファイルを提供することです

すなわち5_ji3uc237uckj92d0jf3932t09ut93f2.pdf:

function user_file($file_name = "") 
{ 
    if ($file_name) 
    { 
     // Ensure no funny business names: 
     $file_name = str_replace ('..', '', $file_name); 
     $file_name = str_replace ('/', '', $file_name); 

     // Check if the user is allowed to access this file 
    $user_id = substr($file_name, 0, strpos($file_name, "_")); 

     // now do the logic to check user is logged in, and user is owner of file 
     (($this->ion_auth->logged_in()) && (($user_id === $this->user->id)) 
     { 
       // Serve file via readfile() 
     } 
    } 
} 

質問:これは人が横断するための他の方法が存在しないことを保証する安全な方法ですディレクトリ、他のファイルへのアクセス権など?

編集1:ユーザーファイルをpublic_htmlの外に格納されてい: ion_authは私の認証ライブラリ、および "の$ this - > USER-> idは"

編集2私の構築物に格納されているユーザーIDです - そしてこれだけ自分のアプリケーションを介してアクセス私の知る限り

編集3:私の改善コード、口座に私は別のファイル拡張子のために収容する必要があるという事実を取って、下の琥珀からのアイデアを使用して、私は試してみるつもりですデータベースのヒットを避ける:

function user_files($file_name = "") 
{ 
    // for security reasons, check the filename is correct 
    // This checks for a 32bit md5 value, followed by a single "." followed by a 3-4 extension (of only a-z) 
    if (preg_match('^[A-Za-z0-9]{32}+[.]{1}[A-Za-z]{3,4}$^', $file_name)) 
    { 
     // Now check the user is logged in 
     if ($this->ion_auth->logged_in()) 
     { 
      // Rewrite the request to the path on my server - and append the user_id onto the filename 
      // This ensures that users can only ever access their own file which they uploaded 
      // As their userid was appended to the filename during the upload! 
      $file = MY_SECURE_FOLDER.$this->user->id.'_'.$file_name; 

      // Now check if file exists 
      if (file_exists($file)) 
      { 
       // Serve the file 
       header('Content-Type: '.get_mime_by_extension($file)); 
       readfile($file); 
      } 
     } 
    } 
} 
+0

ファイルはまだWebアクセス可能なディレクトリにありますか?もしそうなら、あなたの質問に対する答えは** NO **です。 – rdlowrey

+0

こんにちはrdlowrey - ありがとう - 私はファイルがPublic_htmlの外部に格納されている - したがって、アプリケーションを介してのみアクセス可能であることを言及する必要があります - それを考えてくれてありがとう - 私は私の質問を編集します – Laurence

+0

oks。このようなシステムで懸念する唯一のことは、1つのディレクトリにたくさんのファイルがある可能性があることです。 ext3またはWindowsのfat32ファイルディレクトリを持つLinuxサーバでは、readdir()libc呼び出しの使用がルーチンに含まれる場合、パフォーマンス上の問題が発生する可能性があります。 – gview

答えて

2

もっと良いアイデア:ユーザーにMD5を提供させ、ファイル名を自分で作成させてもらいます。そうすれば、ユーザ入力とファイル名の狂った検査を何度も行う必要はありません。MD5が[0-9a-f]という40文字の文字列であることを確認すれば、あなたはうまくいきます。

+0

ありがとうアンバー - 上記の関数はファイル名を取得することです - 私はすでにそれを構築しました。私は、ユーザーがファイル名を要求すると、 "test ../../../ php.ini"のような何かかの悪い名前で何か他のファイルを取得することができないことを確認しようとしています。 ? – Laurence

+1

@Laurencei私はAmberが既にその部分を説明していると信じています。「MD5は[0-9a-f]の40文字の文字列です」 –

+1

@Laurencei by "construct"私は作成を意味するものではありませんファイル;私は、ユーザーが要求しているファイルパスの文字列をまとめることを意味します。あなたの関数は現在、ファイル名全体を取ります。それはより複雑なファイルパスとして検証する必要があるため、悪いことです。 MD5を取るのが良いでしょう - あなたはすでにユーザーのIDを知っていて、ファイル名のパターンを知っているので、MD5を実際にMD5にして、 $ this-> user-> id} _ $ md5.pdf "が存在します。 – Amber

2

私は任意のディレクトリに移動できますが、自分のユーザーIDで始まるファイル名に限定されます。

$file_name = '/./.\\1234_anything.anything'; 
     $file_name = str_replace ('..', '', $file_name); 
     echo $file_name = str_replace ('/', '', $file_name); 

を考慮し、限りファイルパスseperatorsが行くように、/と\は、一般的に等価です。

+0

興味深い - ありがとうクリス – Laurence

関連する問題