17

特定の「ルート」パスの上方../へのトラバースからファイル パス API 入力を保護するために、上向きのディレクトリ トラバーサルの他のすべての複雑な形式など、特別なトラバーサル シーケンスを含むパスを除外できる標準ライブラリ メソッドはありますか?

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

これは、ブロードパス トラバーサル攻撃に似ています。

制限が厳しすぎる (つまり、偽陰性になる可能性がある) メソッドは、これが物事を単純化する場合、私の特定のユース ケースには問題ないかもしれません。日本酒は理論的にはここで機能する可能性があります)。

4

2 に答える 2

30

を使用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;
}
于 2015-10-12T15:05:45.083 に答える
2

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

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

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親ディレクトリへの参照が含まれているか、絶対パスであった場合、 にrelative含まれていないファイルを参照できますroot。この場合、ファイルへの変更が許可される前に例外をスローできます。

于 2015-10-12T14:49:20.767 に答える