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

时间:2015-10-12 14:14:27

标签: java owasp secure-coding path-traversal

是否有任何标准库方法可以过滤掉包含特殊遍历序列的路径,例如../和所有其他复杂形式的向上目录遍历,以保护文件路径API输入不会向上遍历 给定的" root"路径?

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

这类似于更广泛的path traversal attack

限制性太强的方法(即可能导致漏报)可能适用于我的特定用例,如果这简化了事情,而且,我目前的需求是文件系统路径而不是网络路径(尽管是一个Web模块)为了相同的缘故,理论上可以在这里工作)。

2 个答案:

答案 0 :(得分:16)

您可以使用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;
}

答案 1 :(得分:1)

您无需使用第三方库来执行此操作。 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中未包含的文件。在这种情况下,您可以在允许对文件进行任何修改之前抛出异常。