2015-10-12 19 views
10

../などの特殊なトラバーサルシーケンスを含むパスをフィルタリングしてファイルパスAPI入力を保護するための上向きディレクトリトラバーサルのすべての畳み込み形式与えられた「ルート」パスの上向きJava(またはScala)で上向きのパストラバーサルをフィルタリングする

私は、ルートフォルダの値メンバと再帰的に削除するパスを受け付けるメンバ関数を含むクラスを持っています。私の目標は、このAPIを安全にして、入力された入力パスを除外することです。これは、ルートフォルダ値の上向きに変換されます。このクラスは、ルートパスの下のファイルを削除するために自由に使用されますが、ルートパスの上には何も触れることはありません。

これは、より広範なpath traversal attackに似ています。

私の特定のユースケースでは、これを単純化すると、制限が厳しい(偽陰性を招く)方法は問題ありません。また、Webシステムではなくファイルシステムのパスが必要ですモジュールは理論的にはここで働くかもしれません)。

+0

どのようにウェブにそれらのパスを暴露していますか?一般的に、Springのようなフレームワークは、これらの攻撃に対する緩和のためにかなり良い仕事をしているので、他のセキュリティレイヤーを追加する必要はほとんどありません。 – Makoto

+0

私はそうではありません。これは、バックエンドのdevops関連のAPIで、ファイル削除ロジックが含まれているため、OSファイルシステムの権限の助けを借りずに、特定のルートフォルダの外部にあるファイルを削除しないようにする必要があります。 – matanster

+0

ここではどのような道筋がありますか? 'java.nio.file.Path'には相対ファイルパスをベースなどに統合するメソッドがあります。 – biziclop

答えて

0

これを行うには、サードパーティのライブラリを使用する必要はありません。 Javaが提供するファイルAPIは、ファイルが別のファイルの子孫であることを確認する機能を提供します。

Path.resolve(String)は、親ディレクトリ参照、絶対パス、相対パスを解決します。解決方法に絶対パスが引数として渡された場合、絶対パスが返されます。戻り値は、メソッドが呼び出されたパスの子孫であるとは限りません。

Path.startsWith(Path)メソッドを使用すると、パスが別のパスの子孫であることを確認できます。

Path root = java.nio.file.Files.createTempDirectory(null); 
Path relative = root.resolve(pathAsString).normalize(); 
if (!relative.startsWith(root)) { 
    throw new IllegalArgumentException("Path contains invalid characters"); 
} 

pathAsStringが親ディレクトリへの参照が含まれているかrootに含まれていないファイルを参照することができ、絶対パス、relativeました。この場合、ファイルの変更が許可される前に例外をスローすることができます。

+0

それで、なぜそれは機能しますか? **あなた自身を説明してください** ** – Makoto

+0

警告:これをしないでください!この方法は、セキュリティの誤った感覚を与えるので、何もないより悪いです。このチェックをディレクトリトラバーサル攻撃として実行するには、単純に... * traversing *!例: 'pathAsString =" .. ";'。 – Zero3

+0

比較の前に相対パスを正規化する必要があります。私は訂正を反映するために答えを更新しました。 – Aaron

12

Path.normalize()を使用すると、パスから ".."要素(およびその先行要素)を除外できます。 "a/b /../ c"を "a/c"に変換します。パスの開始の「..」を取り除くことはないことに注意してください。これは、除去するための先行するディレクトリコンポーネントもないからです。したがって、別のパスを前に置く場合は、最初に行い、次に結果を正規化します。

Path.startsWith(Path)を使用して、あるパスが別のパスの子孫であるかどうかを確認することもできます。 Path.isAbsolute()は、驚くことではないが、パスが絶対パスか相対パスかを示します。

は、ここで私はAPIに入ってくる信頼されていないパスを処理したい方法は次のとおりです。

/** 
* Resolves an untrusted user-specified path against the API's base directory. 
* Paths that try to escape the base directory are rejected. 
* 
* @param baseDirPath the absolute path of the base directory that all 
        user-specified paths should be within 
* @param userPath the untrusted path provided by the API user, expected to be 
        relative to {@code baseDirPath} 
*/ 
public Path resolvePath(final Path baseDirPath, final Path userPath) { 
    if (!baseDirPath.isAbsolute()) { 
    throw new IllegalArgumentException("Base path must be absolute") 
    } 

    if (userPath.isAbsolute()) { 
    throw new IllegalArgumentException("User path must be relative"); 
    } 

    // Join the two paths together, then normalize so that any ".." elements 
    // in the userPath can remove parts of baseDirPath. 
    // (e.g. "/foo/bar/baz" + "../attack" -> "/foo/bar/attack") 
    final Path resolvedPath = baseDirPath.resolve(userPath).normalize(); 

    // Make sure the resulting path is still within the required directory. 
    // (In the example above, "/foo/bar/attack" is not.) 
    if (!resolvedPath.startsWith(baseDirPath)) { 
    throw new IllegalArgumentException("User path escapes the base path"); 
    } 

    return resolvedPath; 
} 
関連する問題