42

我有一个 Java 服务器实现(TFTP,如果对你很重要),我想确保它不会受到路径遍历攻击,允许访问不应该可用的文件和位置。

到目前为止,我最好的防御尝试是拒绝任何匹配的条目,File.isAbsolute()然后依靠File.getCanonicalPath()解析路径之外的任何.././组件。最后,我确保生成的路径仍在我的服务器所需的根目录中:

public String sanitize(final File dir, final String entry) throws IOException {
    if (entry.length() == 0) {
        throw new PathTraversalException(entry);
    }

    if (new File(entry).isAbsolute()) {
        throw new PathTraversalException(entry);
    }

    final String canonicalDirPath = dir.getCanonicalPath() + File.separator;
    final String canonicalEntryPath = new File(dir, entry).getCanonicalPath();

    if (!canonicalEntryPath.startsWith(canonicalDirPath)) {
        throw new PathTraversalException(entry);
    }

    return canonicalEntryPath.substring(canonicalDirPath.length());
}

是否存在遗漏的安全问题?是否有更好/更快可靠地实现相同结果?

代码需要在 Windows 和 Linux 上一致地工作。

4

3 回答 3

13

以下可能会有所帮助。它比较规范路径和绝对路径,如果它们不同,那么它将失败。仅在 mac/linux 系统上测试(即没有 windows)。

这是针对您希望允许用户提供相对路径而不是绝对路径并且不允许任何父目录引用的情况。

public void failIfDirectoryTraversal(String relativePath)
{
    File file = new File(relativePath);

    if (file.isAbsolute())
    {
        throw new RuntimeException("Directory traversal attempt - absolute path not allowed");
    }

    String pathUsingCanonical;
    String pathUsingAbsolute;
    try
    {
        pathUsingCanonical = file.getCanonicalPath();
        pathUsingAbsolute = file.getAbsolutePath();
    }
    catch (IOException e)
    {
        throw new RuntimeException("Directory traversal attempt?", e);
    }


    // Require the absolute path and canonicalized path match.
    // This is done to avoid directory traversal 
    // attacks, e.g. "1/../2/" 
    if (! pathUsingCanonical.equals(pathUsingAbsolute))
    {
        throw new RuntimeException("Directory traversal attempt?");
    }
}
于 2016-01-07T15:00:17.677 回答
2

如果你在 unix 机器上运行它(我不确定 windows 是否有类似的东西,但它可能)你会想看看 chroot。即使您认为您想尽一切办法让某人参考一些目录,但让操作系统在那里执行这一事实也很好。

(chroot 导致 '/' 引用其他目录,因此“/”可能是“/home/me/project”,而“/../../..”仍然是“/home/me/project”。 )

编辑:

有一个 chroot 系统调用以及一个 chroot 命令行工具。我不知道 Java 是否有本地方法,但没有什么能阻止您使用命令行工具运行服务器。当然,这应该是除了尽最大努力防止其他路径操作之外。

于 2010-03-03T23:48:01.430 回答
-2

您可以检查文件名中允许的字符(http://en.wikipedia.org/wiki/Filename)并过滤掉所有不允许的字符(白名单),然后您可以确定那里有一个文件名。

于 2010-03-04T09:55:23.440 回答