Java 防御路径遍历攻击的最佳方法是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2375903/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 06:42:59  来源:igfitidea点击:

What's the best way to defend against a path traversal attack?

javasecuritypath-traversal

提问by Rob Oxspring

I have a Java server implementation (TFTP if it matters to you) and I'd like to ensure that it's not susceptible to path traversal attacks allowing access to files and locations that shouldn't be available.

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

My best attempt at defending so far is to reject any entries that match File.isAbsolute()and then rely on File.getCanonicalPath()to resolve any ../and ./components out of the path. Finally I ensure that the resulting path is still within the required root directory of my server:

在迄今为止卫冕我的最好的尝试是拒绝任何条目匹配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());
}

Are there security issues that this misses? Are there better / faster to achieve the same result reliably?

这是否存在安全问题?是否有更好/更快的方法来可靠地达到相同的结果?

The code needs to work consistently across Windows and Linux.

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

回答by Sniggerfardimungus

If you're running this on a unix machine (I'm not sure if windows has something similar, but it might) you'll want to look at chroot. Even if you think you hit all the ways for someone to refer up a few directories, it's nice to have the operating system there enforcing the fact.

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

(chroot causes '/' to refer to some other directory, so "/" might be "/home/me/project" and "/../../.." is still "/home/me/project".)

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

EDIT:

编辑:

There's a chroot system call as well as a chroot command-line tool. I don't know if Java has a native method, but nothing would prevent you from running your server with the command-line tool. This should, of course, be in addition to doing your best to prevent other path manipulations.

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

回答by Tower

You could check out the allowed characters in filenames (http://en.wikipedia.org/wiki/Filename) and filter out all non-allowed characters (white listing) and then you could be sure you've got a filename there.

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

回答by Brad Parks

The following may help. It compares the canonical and absolute paths, and if they differ, then it'll fail. Only tested on a mac/linux system (ie no windows).

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

This is for the case where you want to allow the user to supply a relative path, not an absolute path, and you don't allow any parent directory references.

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

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?");
    }
}