在Java(或Scala)中过滤向上路径遍历

mat*_*ter 13 java owasp secure-coding path-traversal

是否有任何的标准库的方法,可以筛选出的路径,其中包括特殊遍历序列,如../和向上目录遍历所有其他回旋形式,从遍历维护文件路径API输入向上给定的"根"的路径?

我有一个包含根文件夹值成员的类,以及一个接受递归删除路径的成员函数.我的目标是使这个API安全,过滤掉提供给它的任何输入路径 - 这将转换为根文件夹值以上的路径.目的是这个类将被广泛用于删除根路径下的文件,但它永远不会触及根路径上的任何东西.

这类似于更广泛的路径遍历攻击.

方法太多的限制(即可能导致假阴性)可能是罚款,我的具体使用情况,如果此简化了的事情,而且,我目前的需求是文件系统路径不是网络的人(虽然,对于相当于一个Web模块在理论上可以在这里工作).

Wyz*_*a-- 18

您可以使用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;
}
Run Code Online (Sandbox Code Playgroud)


Aar*_*ron 3

您不需要使用第三方库来执行此操作。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");
}
Run Code Online (Sandbox Code Playgroud)

pathAsString包含对父目录的引用或者是绝对路径时,relative可以引用root. 在这种情况下,您可以在允许对文件进行任何修改之前引发异常。

  • 比较之前应该对相对路径进行标准化。我更新了答案以反映更正。 (2认同)