2013-04-24 15 views
5

安全な方法で親フォルダに関連してjava.io.Fileインスタンスを作成する方法、つまり、悪意のある攻撃者が親フォルダから脱落するのを防ぐ方法。相対的なjava.io.Fileを作成する安全な方法

例:

String path = request.getParameter("path"); 
    File file = new File(folder, path); 

攻撃者はpathとして私に../../../etc/passwdを送信することがありますので、これは安全でないです。

このようなパスを「クリーン」にするにはどうすればよいですか?

+0

あなたはJavaでそれを必要とする理由セキュリティのこの種は、ファイルのパーミッションによって行われますか? – Dima

+0

_blackフォルダlist_を残して、パスがリストにないことを確認するだけで十分ですか? – Michael

+0

いくつかの興味深いファイルはサーバーでは読み取り可能でなければならない場合があるため、サーバー上で実行されているアプリケーションでは読み取れない可能性があります。 '/ etc/passwd'を読むこと自体はセキュリティ上の問題ではありません。何も損害を与えませんが、その情報から学んだ情報はシステムを攻撃しやすくなります。 –

答えて

3

、私はこの解決策を考え出した:

public static boolean isParent(File parent, File file) { 

    File f; 
    try { 
     parent = parent.getCanonicalFile(); 

     f = file.getCanonicalFile(); 
    } catch(IOException e) { 
     return false; 
    } 

    while(f != null) { 
     // equals() only works for paths that are normalized, hence the need for 
     // getCanonicalFile() above. "a" isn't equal to "./a", for example. 
     if(parent.equals(f)) { 
      return true; 
     } 

     f = f.getParentFile(); 
    } 

    return false; 
} 

ので使用量は次のようになります。

File file = new File(folder, path); 
if(! isParent(folder, file)) { 
    ... deny access ... 
} 

上記のコードはあまり速くない可能性がありますが、他のすべてのソリューションにはセキュリティ上の問題があります。

  • /../|^../|/..$を削除できましたが、Windowsでは動作しません。 Windowsの場合、パターンはより複雑になるとJavaは、Windows上のファイルセパレータとして/を受け入れることを忘れないでください、それはdoesnのため、

    また、パスa/../b/cが有効である(はい、C:/Windows/が有効であるとは同じC:\Windows\手段として)境界を壊していないので、相対的な動きを取り除くだけでは十分ではありません。

  • getCanonicalPath()を使用して2つの文字列を作成し、parentのパスがfileの接頭辞であることを確認してください。しかし、私は、親のパスの後の文字がファイルセパレータであることを確認する必要があります(上記のFile.SEPARATORが十分でない理由を参照)。

2

1つの解決策は、/または..で始まるものを許可しないことです。しかし、私は "安全な/適切な"方法は、(JVM)セキュリティマネージャーを有効にしてアプリケーションを実行し、事前定義された設定以外のファイルへのアクセスを禁止することだと思います。しかし、セキュリティマネージャを有効にするには、ツアーアプリケーションを実行するために必要なすべての権限を把握する必要があります。

OSファイルの許可も重要ですが、明らかです。要求されたよう

編集

は、例を追加しました。例にTomcatに配備現在のプロジェクトからである:他の回答を読んだ後

grant codeBase "file:${catalina.base}/webapps/mywebapp/-" { 
    permission java.io.FilePermission "path/to/folder", "read"; // Anything else will be disallowed 
    // Other required permissions 
} 
+0

javadocによると、 'path'の先頭の'/'は取り除かれます。また、 'doesnotexist /../../ ..'はあなたの計画を破ります。セキュリティマネージャーは良いアイデアのように聞こえるが、正しく設定されたものはまだ見ていない。 –

+0

パスで傷を指摘してくれてありがとう。セキュリティ権限は設定するのが難しいですが、問題が解決されます。 – NilsH

+0

この場合、セキュリティマネージャをどのように設定する必要がありますか? 'folder'はインストールディレクトリからの相対パスであることに注意してください。 –

0
String path = "../../../etc/passwd"; 
    String pureFilename = (new File(path)).getName(); 
    File file = new File(folder, pureFilename); 
+0

興味深い解決策です。 'etc'を保存することはできますか?(相対パス*はサブフォルダを含むかもしれません)? –

+0

しかし、あなたは新しいファイル( "abc/def")で "abc"を失うでしょうgetName() – cahen

+0

同様にパスを得ることができますpurePath =(new File(path))。getParentFile()。getCanonicalPath必要に応じてパスを分析します。 –

-1
boolean isChild(File parent, File child) throws IOException { 
    String parentCanonicalPath = parent.getCanonicalPath(); 
    String childCanonicalPath = child.getCanonicalPath(); 
    return childCanonicalPath.startsWith(parentCanonicalPath); 
} 
+0

parent = 'foo'と子' foobar'(つまり、最後の共通フォルダは異なるが、同じ文字で始まる)を試すまでうまくいくように見えます。 –

関連する問題