【问题标题】:Filtering upwards path traversal in Java (or Scala) [closed]过滤Java(或Scala)中的向上路径遍历[关闭]
【发布时间】:2016-01-10 01:35:33
【问题描述】:

是否有任何标准库方法可以过滤掉包含特殊遍历序列的路径,例如 ../ 和所有其他复杂形式的向上目录遍历,以防止文件路径 API 输入向上遍历 em> 给定的“根”路径?

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

这类似于更广泛的path traversal attack

对于我的特定用例来说,过于严格的方法(即可能导致误报)可能没问题,如果这可以简化事情,而且,我当前的需求是文件系统路径而不是 web 路径(尽管,web 模块出于同等的考虑,理论上可能在这里有效)。

【问题讨论】:

  • 你如何将这些路径暴露给网络?一般来说,像 Spring 这样的框架在缓解这些攻击方面做得相当不错,因此您很少需要在其上添加任何其他安全层。
  • 我不是。这是一个后端devops相关的API,其中包含一些文件删除逻辑,它需要避免在没有OS文件系统权限的帮助下删除给定根文件夹之外的文件。
  • 我们在这里谈论什么样的路径?例如,java.nio.file.Path 具有将相对文件路径合并到基础上的方法。
  • 这可能是一次攻击仍有一些差距。我可以看到它如何成为一个关注,但如果它是一种攻击,那么你必须首先没有正确实现路径遍历。给我们一个 DELETE 请求的例子。
  • 顺便说一句 - 我已经删除了对图书馆的请求,因为这是其他人试图结束这个问题的一个重要原因。它有潜力,但添加库位使其成为一个巨大的目标。

标签: java owasp secure-coding path-traversal


【解决方案1】:

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

【讨论】:

    【解决方案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 中的文件。在这种情况下,您可以在允许对文件进行任何修改之前抛出异常。

    【讨论】:

    • 那为什么有效呢? 解释一下自己。
    • 警告:不要这样做!这种方法比没有更糟糕,因为它给人一种虚假的安全感。您可以通过简单的... traversing 来执行目录遍历攻击!例如:pathAsString = "..";.
    • 相对路径应该在比较之前进行标准化。我更新了答案以反映更正。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-25
    • 1970-01-01
    • 2019-05-05
    • 1970-01-01
    相关资源
    最近更新 更多